Commit d27ba47e authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

parents e3d8b77b dd3e2dcf
......@@ -130,8 +130,6 @@ Code Seq# Include File Comments
<mailto:zapman@interlan.net>
'i' 00-3F linux/i2o.h
'j' 00-3F linux/joystick.h
'k' all asm-sparc/kbio.h
asm-sparc64/kbio.h
'l' 00-3F linux/tcfs_fs.h transparent cryptographic file system
<http://mikonos.dia.unisa.it/tcfs>
'l' 40-7F linux/udf_fs_i.h in development:
......
......@@ -201,6 +201,14 @@ config SUN_OPENPROMFS
Only choose N if you know in advance that you will not need to modify
OpenPROM settings on the running system.
config SPARC_LED
tristate "Sun4m LED driver"
help
This driver toggles the front-panel LED on sun4m systems
in a user-specifyable manner. It's state can be probed
by reading /proc/led and it's blinking mode can be changed
via writes to /proc/led
source "fs/Kconfig.binfmt"
config SUNOS_EMUL
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_SUN_AUXIO) += auxio.o
obj-$(CONFIG_PCI) += ebus.o
obj-$(CONFIG_SUN_PM) += apc.o pmc.o
obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
obj-$(CONFIG_SPARC_LED) += led.o
ifdef CONFIG_SUNOS_EMUL
obj-y += sys_sunos.o sunos_ioctl.o
......
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <asm/auxio.h>
#define LED_MAX_LENGTH 8 /* maximum chars written to proc file */
static inline void led_toggle(void)
{
unsigned char val = get_auxio();
unsigned char on, off;
if (val & AUXIO_LED) {
on = 0;
off = AUXIO_LED;
} else {
on = AUXIO_LED;
off = 0;
}
set_auxio(on, off);
}
static struct timer_list led_blink_timer;
static void led_blink(unsigned long timeout)
{
led_toggle();
/* reschedule */
if (!timeout) { /* blink according to load */
led_blink_timer.expires = jiffies +
((1 + (avenrun[0] >> FSHIFT)) * HZ);
led_blink_timer.data = 0;
} else { /* blink at user specified interval */
led_blink_timer.expires = jiffies + (timeout * HZ);
led_blink_timer.data = timeout;
}
add_timer(&led_blink_timer);
}
static int led_read_proc(char *buf, char **start, off_t offset, int count,
int *eof, void *data)
{
int len = 0;
if (get_auxio() & AUXIO_LED)
len = sprintf(buf, "on\n");
else
len = sprintf(buf, "off\n");
return len;
}
static int led_write_proc(struct file *file, const char *buffer,
unsigned long count, void *data)
{
char *buf = NULL;
if (count > LED_MAX_LENGTH)
count = LED_MAX_LENGTH;
buf = kmalloc(sizeof(char) * (count + 1), GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (copy_from_user(buf, buffer, count)) {
kfree(buf);
return -EFAULT;
}
buf[count] = '\0';
/* work around \n when echo'ing into proc */
if (buf[count - 1] == '\n')
buf[count - 1] = '\0';
/* before we change anything we want to stop any running timers,
* otherwise calls such as on will have no persistent effect
*/
del_timer_sync(&led_blink_timer);
if (!strcmp(buf, "on")) {
auxio_set_led(AUXIO_LED_ON);
} else if (!strcmp(buf, "toggle")) {
led_toggle();
} else if ((*buf > '0') && (*buf <= '9')) {
led_blink(simple_strtoul(buf, NULL, 10));
} else if (!strcmp(buf, "load")) {
led_blink(0);
} else {
auxio_set_led(AUXIO_LED_OFF);
}
kfree(buf);
return count;
}
static struct proc_dir_entry *led;
#define LED_VERSION "0.1"
static int __init led_init(void)
{
init_timer(&led_blink_timer);
led_blink_timer.function = led_blink;
led = create_proc_entry("led", 0, NULL);
if (!led)
return -ENOMEM;
led->read_proc = led_read_proc; /* reader function */
led->write_proc = led_write_proc; /* writer function */
led->owner = THIS_MODULE;
printk(KERN_INFO
"led: version %s, Lars Kotthoff <metalhead@metalhead.ws>\n",
LED_VERSION);
return 0;
}
static void __exit led_exit(void)
{
remove_proc_entry("led", NULL);
del_timer_sync(&led_blink_timer);
}
module_init(led_init);
module_exit(led_exit);
MODULE_AUTHOR("Lars Kotthoff <metalhead@metalhead.ws>");
MODULE_DESCRIPTION("Provides control of the front LED on SPARC systems.");
MODULE_LICENSE("GPL");
MODULE_VERSION(LED_VERSION);
......@@ -23,7 +23,6 @@
#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/file.h>
#include <asm/kbio.h>
#if 0
extern char sunkbd_type;
......
......@@ -11,33 +11,14 @@
#define INCLUDES
#include "compat_ioctl.c"
#include <linux/ncp_fs.h>
#include <linux/syscalls.h>
#include <asm/fbio.h>
#include <asm/kbio.h>
#include <asm/vuid_event.h>
#include <asm/envctrl.h>
#include <asm/display7seg.h>
#include <asm/openpromio.h>
#include <asm/audioio.h>
#include <asm/watchdog.h>
/* Use this to get at 32-bit user passed pointers.
* See sys_sparc32.c for description about it.
*/
#define A(__x) compat_ptr(__x)
static __inline__ void *alloc_user_space(long len)
{
struct pt_regs *regs = current_thread_info()->kregs;
unsigned long usp = regs->u_regs[UREG_I6];
if (!(test_thread_flag(TIF_32BIT)))
usp += STACK_BIAS;
return (void *) (usp - len);
}
#define CODE
#include "compat_ioctl.c"
......@@ -111,357 +92,6 @@ static int fbiogscursor(unsigned int fd, unsigned int cmd, unsigned long arg)
return sys_ioctl (fd, FBIOSCURSOR, (unsigned long)p);
}
#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
/* This really belongs in include/linux/drm.h -DaveM */
#include "../../../drivers/char/drm/drm.h"
typedef struct drm32_version {
int version_major; /* Major version */
int version_minor; /* Minor version */
int version_patchlevel;/* Patch level */
int name_len; /* Length of name buffer */
u32 name; /* Name of driver */
int date_len; /* Length of date buffer */
u32 date; /* User-space buffer to hold date */
int desc_len; /* Length of desc buffer */
u32 desc; /* User-space buffer to hold desc */
} drm32_version_t;
#define DRM32_IOCTL_VERSION DRM_IOWR(0x00, drm32_version_t)
static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_version_t __user *uversion = (drm32_version_t __user *)arg;
drm_version_t __user *p = compat_alloc_user_space(sizeof(*p));
compat_uptr_t addr;
int n;
int ret;
if (clear_user(p, 3 * sizeof(int)) ||
get_user(n, &uversion->name_len) ||
put_user(n, &p->name_len) ||
get_user(addr, &uversion->name) ||
put_user(compat_ptr(addr), &p->name) ||
get_user(n, &uversion->date_len) ||
put_user(n, &p->date_len) ||
get_user(addr, &uversion->date) ||
put_user(compat_ptr(addr), &p->date) ||
get_user(n, &uversion->desc_len) ||
put_user(n, &p->desc_len) ||
get_user(addr, &uversion->desc) ||
put_user(compat_ptr(addr), &p->desc))
return -EFAULT;
ret = sys_ioctl(fd, DRM_IOCTL_VERSION, (unsigned long)p);
if (ret)
return ret;
if (copy_in_user(uversion, p, 3 * sizeof(int)) ||
get_user(n, &p->name_len) ||
put_user(n, &uversion->name_len) ||
get_user(n, &p->date_len) ||
put_user(n, &uversion->date_len) ||
get_user(n, &p->desc_len) ||
put_user(n, &uversion->desc_len))
return -EFAULT;
return 0;
}
typedef struct drm32_unique {
int unique_len; /* Length of unique */
u32 unique; /* Unique name for driver instantiation */
} drm32_unique_t;
#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t)
#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t)
static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_unique_t __user *uarg = (drm32_unique_t __user *)arg;
drm_unique_t __user *p = compat_alloc_user_space(sizeof(*p));
compat_uptr_t addr;
int n;
int ret;
if (get_user(n, &uarg->unique_len) ||
put_user(n, &p->unique_len) ||
get_user(addr, &uarg->unique) ||
put_user(compat_ptr(addr), &p->unique))
return -EFAULT;
if (cmd == DRM32_IOCTL_GET_UNIQUE)
ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)p);
else
ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)p);
if (ret)
return ret;
if (get_user(n, &p->unique_len) || put_user(n, &uarg->unique_len))
return -EFAULT;
return 0;
}
typedef struct drm32_map {
u32 offset; /* Requested physical address (0 for SAREA)*/
u32 size; /* Requested physical size (bytes) */
drm_map_type_t type; /* Type of memory to map */
drm_map_flags_t flags; /* Flags */
u32 handle; /* User-space: "Handle" to pass to mmap */
/* Kernel-space: kernel-virtual address */
int mtrr; /* MTRR slot used */
/* Private data */
} drm32_map_t;
#define DRM32_IOCTL_ADD_MAP DRM_IOWR(0x15, drm32_map_t)
static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_map_t __user *uarg = (drm32_map_t __user *) arg;
drm_map_t karg;
mm_segment_t old_fs;
u32 tmp;
int ret;
ret = get_user(karg.offset, &uarg->offset);
ret |= get_user(karg.size, &uarg->size);
ret |= get_user(karg.type, &uarg->type);
ret |= get_user(karg.flags, &uarg->flags);
ret |= get_user(tmp, &uarg->handle);
ret |= get_user(karg.mtrr, &uarg->mtrr);
if (ret)
return -EFAULT;
karg.handle = (void *) (unsigned long) tmp;
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg);
set_fs(old_fs);
if (!ret) {
ret = put_user(karg.offset, &uarg->offset);
ret |= put_user(karg.size, &uarg->size);
ret |= put_user(karg.type, &uarg->type);
ret |= put_user(karg.flags, &uarg->flags);
tmp = (u32) (long)karg.handle;
ret |= put_user(tmp, &uarg->handle);
ret |= put_user(karg.mtrr, &uarg->mtrr);
if (ret)
ret = -EFAULT;
}
return ret;
}
typedef struct drm32_buf_info {
int count; /* Entries in list */
u32 list; /* (drm_buf_desc_t *) */
} drm32_buf_info_t;
#define DRM32_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm32_buf_info_t)
static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_buf_info_t __user *uarg = (drm32_buf_info_t __user *)arg;
drm_buf_info_t __user *p = compat_alloc_user_space(sizeof(*p));
compat_uptr_t addr;
int n;
int ret;
if (get_user(n, &uarg->count) || put_user(n, &p->count) ||
get_user(addr, &uarg->list) || put_user(compat_ptr(addr), &p->list))
return -EFAULT;
ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long)p);
if (ret)
return ret;
if (get_user(n, &p->count) || put_user(n, &uarg->count))
return -EFAULT;
return 0;
}
typedef struct drm32_buf_free {
int count;
u32 list; /* (int *) */
} drm32_buf_free_t;
#define DRM32_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm32_buf_free_t)
static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_buf_free_t __user *uarg = (drm32_buf_free_t __user *)arg;
drm_buf_free_t __user *p = compat_alloc_user_space(sizeof(*p));
compat_uptr_t addr;
int n;
if (get_user(n, &uarg->count) || put_user(n, &p->count) ||
get_user(addr, &uarg->list) || put_user(compat_ptr(addr), &p->list))
return -EFAULT;
return sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long)p);
}
typedef struct drm32_buf_pub {
int idx; /* Index into master buflist */
int total; /* Buffer size */
int used; /* Amount of buffer in use (for DMA) */
u32 address; /* Address of buffer (void *) */
} drm32_buf_pub_t;
typedef struct drm32_buf_map {
int count; /* Length of buflist */
u32 virtual; /* Mmaped area in user-virtual (void *) */
u32 list; /* Buffer information (drm_buf_pub_t *) */
} drm32_buf_map_t;
#define DRM32_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm32_buf_map_t)
static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_buf_map_t __user *uarg = (drm32_buf_map_t __user *)arg;
drm32_buf_pub_t __user *ulist;
drm_buf_map_t __user *arg64;
drm_buf_pub_t __user *list;
int orig_count, ret, i;
int n;
compat_uptr_t addr;
if (get_user(orig_count, &uarg->count))
return -EFAULT;
arg64 = compat_alloc_user_space(sizeof(drm_buf_map_t) +
(size_t)orig_count * sizeof(drm_buf_pub_t));
list = (void __user *)(arg64 + 1);
if (put_user(orig_count, &arg64->count) ||
put_user(list, &arg64->list) ||
get_user(addr, &uarg->virtual) ||
put_user(compat_ptr(addr), &arg64->virtual) ||
get_user(addr, &uarg->list))
return -EFAULT;
ulist = compat_ptr(addr);
for (i = 0; i < orig_count; i++) {
if (get_user(n, &ulist[i].idx) ||
put_user(n, &list[i].idx) ||
get_user(n, &ulist[i].total) ||
put_user(n, &list[i].total) ||
get_user(n, &ulist[i].used) ||
put_user(n, &list[i].used) ||
get_user(addr, &ulist[i].address) ||
put_user(compat_ptr(addr), &list[i].address))
return -EFAULT;
}
ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) arg64);
if (ret)
return ret;
for (i = 0; i < orig_count; i++) {
void __user *p;
if (get_user(n, &list[i].idx) ||
put_user(n, &ulist[i].idx) ||
get_user(n, &list[i].total) ||
put_user(n, &ulist[i].total) ||
get_user(n, &list[i].used) ||
put_user(n, &ulist[i].used) ||
get_user(p, &list[i].address) ||
put_user((unsigned long)p, &ulist[i].address))
return -EFAULT;
}
if (get_user(n, &arg64->count) || put_user(n, &uarg->count))
return -EFAULT;
return 0;
}
typedef struct drm32_dma {
/* Indices here refer to the offset into
buflist in drm_buf_get_t. */
int context; /* Context handle */
int send_count; /* Number of buffers to send */
u32 send_indices; /* List of handles to buffers (int *) */
u32 send_sizes; /* Lengths of data to send (int *) */
drm_dma_flags_t flags; /* Flags */
int request_count; /* Number of buffers requested */
int request_size; /* Desired size for buffers */
u32 request_indices; /* Buffer information (int *) */
u32 request_sizes; /* (int *) */
int granted_count; /* Number of buffers granted */
} drm32_dma_t;
#define DRM32_IOCTL_DMA DRM_IOWR(0x29, drm32_dma_t)
/* RED PEN The DRM layer blindly dereferences the send/request
* index/size arrays even though they are userland
* pointers. -DaveM
*/
static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_dma_t __user *uarg = (drm32_dma_t __user *) arg;
drm_dma_t __user *p = compat_alloc_user_space(sizeof(*p));
compat_uptr_t addr;
int ret;
if (copy_in_user(p, uarg, 2 * sizeof(int)) ||
get_user(addr, &uarg->send_indices) ||
put_user(compat_ptr(addr), &p->send_indices) ||
get_user(addr, &uarg->send_sizes) ||
put_user(compat_ptr(addr), &p->send_sizes) ||
copy_in_user(&p->flags, &uarg->flags, sizeof(drm_dma_flags_t)) ||
copy_in_user(&p->request_count, &uarg->request_count, sizeof(int))||
copy_in_user(&p->request_size, &uarg->request_size, sizeof(int)) ||
get_user(addr, &uarg->request_indices) ||
put_user(compat_ptr(addr), &p->request_indices) ||
get_user(addr, &uarg->request_sizes) ||
put_user(compat_ptr(addr), &p->request_sizes) ||
copy_in_user(&p->granted_count, &uarg->granted_count, sizeof(int)))
return -EFAULT;
ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long)p);
if (ret)
return ret;
if (copy_in_user(uarg, p, 2 * sizeof(int)) ||
copy_in_user(&uarg->flags, &p->flags, sizeof(drm_dma_flags_t)) ||
copy_in_user(&uarg->request_count, &p->request_count, sizeof(int))||
copy_in_user(&uarg->request_size, &p->request_size, sizeof(int)) ||
copy_in_user(&uarg->granted_count, &p->granted_count, sizeof(int)))
return -EFAULT;
return 0;
}
typedef struct drm32_ctx_res {
int count;
u32 contexts; /* (drm_ctx_t *) */
} drm32_ctx_res_t;
#define DRM32_IOCTL_RES_CTX DRM_IOWR(0x26, drm32_ctx_res_t)
static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
{
drm32_ctx_res_t __user *uarg = (drm32_ctx_res_t __user *) arg;
drm_ctx_res_t __user *p = compat_alloc_user_space(sizeof(*p));
compat_uptr_t addr;
int ret;
if (copy_in_user(p, uarg, sizeof(int)) ||
get_user(addr, &uarg->contexts) ||
put_user(compat_ptr(addr), &p->contexts))
return -EFAULT;
ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long)p);
if (ret)
return ret;
if (copy_in_user(uarg, p, sizeof(int)))
return -EFAULT;
return 0;
}
#endif
typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL((cmd),sys_ioctl)
......@@ -485,103 +115,14 @@ COMPATIBLE_IOCTL(FBIOSCURPOS)
COMPATIBLE_IOCTL(FBIOGCURPOS)
COMPATIBLE_IOCTL(FBIOGCURMAX)
/* Little k */
COMPATIBLE_IOCTL(KIOCTYPE)
COMPATIBLE_IOCTL(KIOCLAYOUT)
COMPATIBLE_IOCTL(KIOCGTRANS)
COMPATIBLE_IOCTL(KIOCTRANS)
COMPATIBLE_IOCTL(KIOCCMD)
COMPATIBLE_IOCTL(KIOCSDIRECT)
COMPATIBLE_IOCTL(KIOCSLED)
COMPATIBLE_IOCTL(KIOCGLED)
COMPATIBLE_IOCTL(KIOCSRATE)
COMPATIBLE_IOCTL(KIOCGRATE)
COMPATIBLE_IOCTL(VUIDSFORMAT)
COMPATIBLE_IOCTL(VUIDGFORMAT)
/* Little v, the video4linux ioctls */
COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
COMPATIBLE_IOCTL(ENVCTRL_RD_WARNING_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_SHUTDOWN_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_CPU_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_FAN_STATUS)
COMPATIBLE_IOCTL(ENVCTRL_RD_VOLTAGE_STATUS)
COMPATIBLE_IOCTL(ENVCTRL_RD_SCSI_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_ETHERNET_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_MTHRBD_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_CPU_VOLTAGE)
COMPATIBLE_IOCTL(ENVCTRL_RD_GLOBALADDRESS)
/* COMPATIBLE_IOCTL(D7SIOCRD) same value as ENVCTRL_RD_VOLTAGE_STATUS */
COMPATIBLE_IOCTL(D7SIOCWR)
COMPATIBLE_IOCTL(D7SIOCTM)
/* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have
* embedded pointers in the arg which we'd need to clean up...
*/
COMPATIBLE_IOCTL(OPROMGETOPT)
COMPATIBLE_IOCTL(OPROMSETOPT)
COMPATIBLE_IOCTL(OPROMNXTOPT)
COMPATIBLE_IOCTL(OPROMSETOPT2)
COMPATIBLE_IOCTL(OPROMNEXT)
COMPATIBLE_IOCTL(OPROMCHILD)
COMPATIBLE_IOCTL(OPROMGETPROP)
COMPATIBLE_IOCTL(OPROMNXTPROP)
COMPATIBLE_IOCTL(OPROMU2P)
COMPATIBLE_IOCTL(OPROMGETCONS)
COMPATIBLE_IOCTL(OPROMGETFBNAME)
COMPATIBLE_IOCTL(OPROMGETBOOTARGS)
COMPATIBLE_IOCTL(OPROMSETCUR)
COMPATIBLE_IOCTL(OPROMPCI2NODE)
COMPATIBLE_IOCTL(OPROMPATH2NODE)
/* Big L */
COMPATIBLE_IOCTL(LOOP_SET_STATUS64)
COMPATIBLE_IOCTL(LOOP_GET_STATUS64)
/* Big A */
COMPATIBLE_IOCTL(AUDIO_GETINFO)
COMPATIBLE_IOCTL(AUDIO_SETINFO)
COMPATIBLE_IOCTL(AUDIO_DRAIN)
COMPATIBLE_IOCTL(AUDIO_GETDEV)
COMPATIBLE_IOCTL(AUDIO_GETDEV_SUNOS)
COMPATIBLE_IOCTL(AUDIO_FLUSH)
COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC)
COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK)
COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK)
COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL)
COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS)
COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS)
COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX)
COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW)
COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW)
COMPATIBLE_IOCTL(DRM_IOCTL_LOCK)
COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
#endif /* DRM */
COMPATIBLE_IOCTL(WIOCSTART)
COMPATIBLE_IOCTL(WIOCSTOP)
COMPATIBLE_IOCTL(WIOCGSTAT)
/* And these ioctls need translation */
/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
HANDLE_IOCTL(FBIOPUTCMAP32, fbiogetputcmap)
HANDLE_IOCTL(FBIOGETCMAP32, fbiogetputcmap)
HANDLE_IOCTL(FBIOSCURSOR32, fbiogscursor)
#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version)
HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique)
HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique)
HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap)
HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs)
HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs)
HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs)
HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma)
HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx)
#endif /* DRM */
#if 0
HANDLE_IOCTL(RTC32_IRQP_READ, do_rtc_ioctl)
HANDLE_IOCTL(RTC32_IRQP_SET, do_rtc_ioctl)
......
......@@ -154,6 +154,7 @@ int prom_callback(long *args)
pud_t *pudp;
pmd_t *pmdp;
pte_t *ptep;
pte_t pte;
for_each_process(p) {
mm = p->mm;
......@@ -178,8 +179,9 @@ int prom_callback(long *args)
* being called from inside OBP.
*/
ptep = pte_offset_map(pmdp, va);
if (pte_present(*ptep)) {
tte = pte_val(*ptep);
pte = *ptep;
if (pte_present(pte)) {
tte = pte_val(pte);
res = PROM_TRUE;
}
pte_unmap(ptep);
......@@ -218,6 +220,7 @@ int prom_callback(long *args)
pud_t *pudp;
pmd_t *pmdp;
pte_t *ptep;
pte_t pte;
int error;
if ((va >= LOW_OBP_ADDRESS) && (va < HI_OBP_ADDRESS)) {
......@@ -240,8 +243,9 @@ int prom_callback(long *args)
* being called from inside OBP.
*/
ptep = pte_offset_kernel(pmdp, va);
if (pte_present(*ptep)) {
tte = pte_val(*ptep);
pte = *ptep;
if (pte_present(pte)) {
tte = pte_val(pte);
res = PROM_TRUE;
}
goto done;
......
......@@ -863,6 +863,7 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
pud_t *pudp = pud_offset(pgdp, address);
pmd_t *pmdp = pmd_offset(pudp, address);
pte_t *ptep;
pte_t pte;
regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
......@@ -873,9 +874,10 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
preempt_disable();
ptep = pte_offset_map(pmdp, address);
if (pte_present(*ptep)) {
pte = *ptep;
if (pte_present(pte)) {
unsigned long page = (unsigned long)
page_address(pte_page(*ptep));
page_address(pte_page(pte));
wmb();
__asm__ __volatile__("flush %0 + %1"
......
......@@ -839,43 +839,29 @@ void smp_flush_tlb_all(void)
* questionable (in theory the big win for threads is the massive sharing of
* address space state across processors).
*/
/* This currently is only used by the hugetlb arch pre-fault
* hook on UltraSPARC-III+ and later when changing the pagesize
* bits of the context register for an address space.
*/
void smp_flush_tlb_mm(struct mm_struct *mm)
{
/*
* This code is called from two places, dup_mmap and exit_mmap. In the
* former case, we really need a flush. In the later case, the callers
* are single threaded exec_mmap (really need a flush), multithreaded
* exec_mmap case (do not need to flush, since the caller gets a new
* context via activate_mm), and all other callers of mmput() whence
* the flush can be optimized since the associated threads are dead and
* the mm is being torn down (__exit_mm and other mmput callers) or the
* owning thread is dissociating itself from the mm. The
* (atomic_read(&mm->mm_users) == 0) check ensures real work is done
* for single thread exec and dup_mmap cases. An alternate check might
* have been (current->mm != mm).
* Kanoj Sarcar
*/
if (atomic_read(&mm->mm_users) == 0)
return;
{
u32 ctx = CTX_HWBITS(mm->context);
int cpu = get_cpu();
u32 ctx = CTX_HWBITS(mm->context);
int cpu = get_cpu();
if (atomic_read(&mm->mm_users) == 1) {
mm->cpu_vm_mask = cpumask_of_cpu(cpu);
goto local_flush_and_out;
}
if (atomic_read(&mm->mm_users) == 1) {
mm->cpu_vm_mask = cpumask_of_cpu(cpu);
goto local_flush_and_out;
}
smp_cross_call_masked(&xcall_flush_tlb_mm,
ctx, 0, 0,
mm->cpu_vm_mask);
smp_cross_call_masked(&xcall_flush_tlb_mm,
ctx, 0, 0,
mm->cpu_vm_mask);
local_flush_and_out:
__flush_tlb_mm(ctx, SECONDARY_CONTEXT);
local_flush_and_out:
__flush_tlb_mm(ctx, SECONDARY_CONTEXT);
put_cpu();
}
put_cpu();
}
void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long *vaddrs)
......@@ -883,34 +869,13 @@ void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long
u32 ctx = CTX_HWBITS(mm->context);
int cpu = get_cpu();
if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) {
if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1)
mm->cpu_vm_mask = cpumask_of_cpu(cpu);
goto local_flush_and_out;
} else {
/* This optimization is not valid. Normally
* we will be holding the page_table_lock, but
* there is an exception which is copy_page_range()
* when forking. The lock is held during the individual
* page table updates in the parent, but not at the
* top level, which is where we are invoked.
*/
if (0) {
cpumask_t this_cpu_mask = cpumask_of_cpu(cpu);
/* By virtue of running under the mm->page_table_lock,
* and mmu_context.h:switch_mm doing the same, the
* following operation is safe.
*/
if (cpus_equal(mm->cpu_vm_mask, this_cpu_mask))
goto local_flush_and_out;
}
}
smp_cross_call_masked(&xcall_flush_tlb_pending,
ctx, nr, (unsigned long) vaddrs,
mm->cpu_vm_mask);
else
smp_cross_call_masked(&xcall_flush_tlb_pending,
ctx, nr, (unsigned long) vaddrs,
mm->cpu_vm_mask);
local_flush_and_out:
__flush_tlb_pending(ctx, nr, vaddrs);
put_cpu();
......
......@@ -24,7 +24,6 @@
#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/compat.h>
#include <asm/kbio.h>
#define SUNOS_NR_OPEN 256
......
......@@ -60,17 +60,6 @@ static void __iomem *mstk48t59_regs;
static int set_rtc_mmss(unsigned long);
static __init unsigned long dummy_get_tick(void)
{
return 0;
}
static __initdata struct sparc64_tick_ops dummy_tick_ops = {
.get_tick = dummy_get_tick,
};
struct sparc64_tick_ops *tick_ops __read_mostly = &dummy_tick_ops;
#define TICK_PRIV_BIT (1UL << 63)
#ifdef CONFIG_SMP
......@@ -200,6 +189,8 @@ static struct sparc64_tick_ops tick_operations __read_mostly = {
.softint_mask = 1UL << 0,
};
struct sparc64_tick_ops *tick_ops __read_mostly = &tick_operations;
static void stick_init_tick(unsigned long offset)
{
tick_disable_protection();
......
......@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/smp_lock.h>
#include <asm/irq.h>
#include <asm/ebus.h>
#include <asm/oplib.h>
......@@ -394,6 +395,28 @@ static int wd_ioctl(struct inode *inode, struct file *file,
return(0);
}
static long wd_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int rval = -ENOIOCTLCMD;
switch (cmd) {
/* solaris ioctls are specific to this driver */
case WIOCSTART:
case WIOCSTOP:
case WIOCGSTAT:
lock_kernel();
rval = wd_ioctl(file->f_dentry->d_inode, file, cmd, arg);
lock_kernel();
break;
/* everything else is handled by the generic compat layer */
default:
break;
}
return rval;
}
static ssize_t wd_write(struct file *file,
const char __user *buf,
size_t count,
......@@ -441,6 +464,7 @@ static irqreturn_t wd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct file_operations wd_fops = {
.owner = THIS_MODULE,
.ioctl = wd_ioctl,
.compat_ioctl = wd_compat_ioctl,
.open = wd_open,
.write = wd_write,
.read = wd_read,
......
......@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h> /* request_region */
#include <linux/smp_lock.h>
#include <asm/atomic.h>
#include <asm/ebus.h> /* EBus device */
#include <asm/oplib.h> /* OpenProm Library */
......@@ -114,22 +115,25 @@ static int d7s_release(struct inode *inode, struct file *f)
return 0;
}
static int d7s_ioctl(struct inode *inode, struct file *f,
unsigned int cmd, unsigned long arg)
static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
__u8 regs = readb(d7s_regs);
__u8 ireg = 0;
int error = 0
if (D7S_MINOR != iminor(inode))
if (D7S_MINOR != iminor(file->f_dentry->d_inode))
return -ENODEV;
lock_kernel();
switch (cmd) {
case D7SIOCWR:
/* assign device register values
* we mask-out D7S_FLIP if in sol_compat mode
*/
if (get_user(ireg, (int __user *) arg))
return -EFAULT;
if (get_user(ireg, (int __user *) arg)) {
error = -EFAULT;
break;
}
if (0 != sol_compat) {
(regs & D7S_FLIP) ?
(ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP);
......@@ -144,8 +148,10 @@ static int d7s_ioctl(struct inode *inode, struct file *f,
* This driver will not misinform you about the state
* of your hardware while in sol_compat mode
*/
if (put_user(regs, (int __user *) arg))
return -EFAULT;
if (put_user(regs, (int __user *) arg)) {
error = -EFAULT;
break;
}
break;
case D7SIOCTM:
......@@ -155,15 +161,17 @@ static int d7s_ioctl(struct inode *inode, struct file *f,
writeb(regs, d7s_regs);
break;
};
lock_kernel();
return 0;
return error;
}
static struct file_operations d7s_fops = {
.owner = THIS_MODULE,
.ioctl = d7s_ioctl,
.open = d7s_open,
.release = d7s_release,
.owner = THIS_MODULE,
.unlocked_ioctl = d7s_ioctl,
.compat_ioctl = d7s_ioctl,
.open = d7s_open,
.release = d7s_release,
};
static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops };
......
......@@ -654,9 +654,8 @@ envctrl_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
/* Function Description: Command what to read. Mapped to user ioctl().
* Return: Gives 0 for implemented commands, -EINVAL otherwise.
*/
static int
envctrl_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long
envctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
char __user *infobuf;
......@@ -715,11 +714,14 @@ envctrl_release(struct inode *inode, struct file *file)
}
static struct file_operations envctrl_fops = {
.owner = THIS_MODULE,
.read = envctrl_read,
.ioctl = envctrl_ioctl,
.open = envctrl_open,
.release = envctrl_release,
.owner = THIS_MODULE,
.read = envctrl_read,
.unlocked_ioctl = envctrl_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = envctrl_ioctl,
#endif
.open = envctrl_open,
.release = envctrl_release,
};
static struct miscdevice envctrl_dev = {
......
......@@ -39,6 +39,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/oplib.h>
......@@ -565,6 +566,38 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
}
}
static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
long rval = -ENOTTY;
/*
* SunOS/Solaris only, the NetBSD one's have embedded pointers in
* the arg which we'd need to clean up...
*/
switch (cmd) {
case OPROMGETOPT:
case OPROMSETOPT:
case OPROMNXTOPT:
case OPROMSETOPT2:
case OPROMNEXT:
case OPROMCHILD:
case OPROMGETPROP:
case OPROMNXTPROP:
case OPROMU2P:
case OPROMGETCONS:
case OPROMGETFBNAME:
case OPROMGETBOOTARGS:
case OPROMSETCUR:
case OPROMPCI2NODE:
case OPROMPATH2NODE:
lock_kernel();
rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg);
lock_kernel();
break;
}
}
static int openprom_open(struct inode * inode, struct file * file)
{
DATA *data;
......
......@@ -1441,7 +1441,7 @@ static void sunsu_console_write(struct console *co, const char *s,
* - initialize the serial port
* Return non-zero if we didn't find a serial port.
*/
static int __init sunsu_console_setup(struct console *co, char *options)
static int sunsu_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 9600;
......
......@@ -653,12 +653,6 @@ static void cg6_chip_init(struct fb_info *info)
sbus_writel(0, &fbc->clipminy);
sbus_writel(info->var.xres - 1, &fbc->clipmaxx);
sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
/* Disable cursor in Brooktree DAC. */
sbus_writel(0x06 << 24, &par->bt->addr);
tmp = sbus_readl(&par->bt->control);
tmp &= ~(0x03 << 24);
sbus_writel(tmp, &par->bt->control);
}
struct all_info {
......
#include <asm-sparc/kbio.h>
#ifndef _M68K_VUID_EVENT_H
#define _M68K_VUID_EVENT_H
#include <asm-sparc/vuid_event.h>
#endif
/*
* include/asm-sparc/audioio.h
*
* Sparc Audio Midlayer
* Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
*/
#ifndef _AUDIOIO_H_
#define _AUDIOIO_H_
/*
* SunOS/Solaris /dev/audio interface
*/
#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
#include <linux/types.h>
#include <linux/time.h>
#include <linux/ioctl.h>
#endif
/*
* This structure contains state information for audio device IO streams.
*/
typedef struct audio_prinfo {
/*
* The following values describe the audio data encoding.
*/
unsigned int sample_rate; /* samples per second */
unsigned int channels; /* number of interleaved channels */
unsigned int precision; /* bit-width of each sample */
unsigned int encoding; /* data encoding method */
/*
* The following values control audio device configuration
*/
unsigned int gain; /* gain level: 0 - 255 */
unsigned int port; /* selected I/O port (see below) */
unsigned int avail_ports; /* available I/O ports (see below) */
unsigned int _xxx[2]; /* Reserved for future use */
unsigned int buffer_size; /* I/O buffer size */
/*
* The following values describe driver state
*/
unsigned int samples; /* number of samples converted */
unsigned int eof; /* End Of File counter (play only) */
unsigned char pause; /* non-zero for pause, zero to resume */
unsigned char error; /* non-zero if overflow/underflow */
unsigned char waiting; /* non-zero if a process wants access */
unsigned char balance; /* stereo channel balance */
unsigned short minordev;
/*
* The following values are read-only state flags
*/
unsigned char open; /* non-zero if open access permitted */
unsigned char active; /* non-zero if I/O is active */
} audio_prinfo_t;
/*
* This structure describes the current state of the audio device.
*/
typedef struct audio_info {
/*
* Per-stream information
*/
audio_prinfo_t play; /* output status information */
audio_prinfo_t record; /* input status information */
/*
* Per-unit/channel information
*/
unsigned int monitor_gain; /* input to output mix: 0 - 255 */
unsigned char output_muted; /* non-zero if output is muted */
unsigned char _xxx[3]; /* Reserved for future use */
unsigned int _yyy[3]; /* Reserved for future use */
} audio_info_t;
/*
* Audio encoding types
*/
#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */
#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */
#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */
#define AUDIO_ENCODING_LINEAR (3) /* Linear PCM encoding */
#define AUDIO_ENCODING_FLOAT (4) /* IEEE float (-1. <-> +1.) */
#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */
#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */
#define AUDIO_ENCODING_LINEARLE (106) /* Linear PCM LE encoding */
/*
* These ranges apply to record, play, and monitor gain values
*/
#define AUDIO_MIN_GAIN (0) /* minimum gain value */
#define AUDIO_MAX_GAIN (255) /* maximum gain value */
/*
* These values apply to the balance field to adjust channel gain values
*/
#define AUDIO_LEFT_BALANCE (0) /* left channel only */
#define AUDIO_MID_BALANCE (32) /* equal left/right channel */
#define AUDIO_RIGHT_BALANCE (64) /* right channel only */
#define AUDIO_BALANCE_SHIFT (3)
/*
* Generic minimum/maximum limits for number of channels, both modes
*/
#define AUDIO_MIN_PLAY_CHANNELS (1)
#define AUDIO_MAX_PLAY_CHANNELS (4)
#define AUDIO_MIN_REC_CHANNELS (1)
#define AUDIO_MAX_REC_CHANNELS (4)
/*
* Generic minimum/maximum limits for sample precision
*/
#define AUDIO_MIN_PLAY_PRECISION (8)
#define AUDIO_MAX_PLAY_PRECISION (32)
#define AUDIO_MIN_REC_PRECISION (8)
#define AUDIO_MAX_REC_PRECISION (32)
/*
* Define some convenient names for typical audio ports
*/
/*
* output ports (several may be enabled simultaneously)
*/
#define AUDIO_SPEAKER 0x01 /* output to built-in speaker */
#define AUDIO_HEADPHONE 0x02 /* output to headphone jack */
#define AUDIO_LINE_OUT 0x04 /* output to line out */
/*
* input ports (usually only one at a time)
*/
#define AUDIO_MICROPHONE 0x01 /* input from microphone */
#define AUDIO_LINE_IN 0x02 /* input from line in */
#define AUDIO_CD 0x04 /* input from on-board CD inputs */
#define AUDIO_INTERNAL_CD_IN AUDIO_CD /* input from internal CDROM */
#define AUDIO_ANALOG_LOOPBACK 0x40 /* input from output */
/*
* This macro initializes an audio_info structure to 'harmless' values.
* Note that (~0) might not be a harmless value for a flag that was
* a signed int.
*/
#define AUDIO_INITINFO(i) { \
unsigned int *__x__; \
for (__x__ = (unsigned int *)(i); \
(char *) __x__ < (((char *)(i)) + sizeof (audio_info_t)); \
*__x__++ = ~0); \
}
/*
* These allow testing for what the user wants to set
*/
#define AUD_INITVALUE (~0)
#define Modify(X) ((unsigned int)(X) != AUD_INITVALUE)
#define Modifys(X) ((X) != (unsigned short)AUD_INITVALUE)
#define Modifyc(X) ((X) != (unsigned char)AUD_INITVALUE)
/*
* Parameter for the AUDIO_GETDEV ioctl to determine current
* audio devices.
*/
#define MAX_AUDIO_DEV_LEN (16)
typedef struct audio_device {
char name[MAX_AUDIO_DEV_LEN];
char version[MAX_AUDIO_DEV_LEN];
char config[MAX_AUDIO_DEV_LEN];
} audio_device_t;
/*
* Ioctl calls for the audio device.
*/
/*
* AUDIO_GETINFO retrieves the current state of the audio device.
*
* AUDIO_SETINFO copies all fields of the audio_info structure whose
* values are not set to the initialized value (-1) to the device state.
* It performs an implicit AUDIO_GETINFO to return the new state of the
* device. Note that the record.samples and play.samples fields are set
* to the last value before the AUDIO_SETINFO took effect. This allows
* an application to reset the counters while atomically retrieving the
* last value.
*
* AUDIO_DRAIN suspends the calling process until the write buffers are
* empty.
*
* AUDIO_GETDEV returns a structure of type audio_device_t which contains
* three strings. The string "name" is a short identifying string (for
* example, the SBus Fcode name string), the string "version" identifies
* the current version of the device, and the "config" string identifies
* the specific configuration of the audio stream. All fields are
* device-dependent -- see the device specific manual pages for details.
*
* AUDIO_GETDEV_SUNOS returns a number which is an audio device defined
* herein (making it not too portable)
*
* AUDIO_FLUSH stops all playback and recording, clears all queued buffers,
* resets error counters, and restarts recording and playback as appropriate
* for the current sampling mode.
*/
#define AUDIO_GETINFO _IOR('A', 1, audio_info_t)
#define AUDIO_SETINFO _IOWR('A', 2, audio_info_t)
#define AUDIO_DRAIN _IO('A', 3)
#define AUDIO_GETDEV _IOR('A', 4, audio_device_t)
#define AUDIO_GETDEV_SUNOS _IOR('A', 4, int)
#define AUDIO_FLUSH _IO('A', 5)
/* Define possible audio hardware configurations for
* old SunOS-style AUDIO_GETDEV ioctl */
#define AUDIO_DEV_UNKNOWN (0) /* not defined */
#define AUDIO_DEV_AMD (1) /* audioamd device */
#define AUDIO_DEV_SPEAKERBOX (2) /* dbri device with speakerbox */
#define AUDIO_DEV_CODEC (3) /* dbri device (internal speaker) */
#define AUDIO_DEV_CS4231 (5) /* cs4231 device */
/*
* The following ioctl sets the audio device into an internal loopback mode,
* if the hardware supports this. The argument is TRUE to set loopback,
* FALSE to reset to normal operation. If the hardware does not support
* internal loopback, the ioctl should fail with EINVAL.
* Causes ADC data to be digitally mixed in and sent to the DAC.
*/
#define AUDIO_DIAG_LOOPBACK _IOW('A', 101, int)
#endif /* _AUDIOIO_H_ */
#ifndef __LINUX_KBIO_H
#define __LINUX_KBIO_H
/* Return keyboard type */
#define KIOCTYPE _IOR('k', 9, int)
/* Return Keyboard layout */
#define KIOCLAYOUT _IOR('k', 20, int)
enum {
TR_NONE,
TR_ASCII, /* keyboard is in regular state */
TR_EVENT, /* keystrokes sent as firm events */
TR_UNTRANS_EVENT /* EVENT+up and down+no translation */
};
/* Return the current keyboard translation */
#define KIOCGTRANS _IOR('k', 5, int)
/* Set the keyboard translation */
#define KIOCTRANS _IOW('k', 0, int)
/* Send a keyboard command */
#define KIOCCMD _IOW('k', 8, int)
/* Return if keystrokes are being sent to /dev/kbd */
/* Set routing of keystrokes to /dev/kbd */
#define KIOCSDIRECT _IOW('k', 10, int)
/* Set keyboard leds */
#define KIOCSLED _IOW('k', 14, unsigned char)
/* Get keyboard leds */
#define KIOCGLED _IOR('k', 15, unsigned char)
/* Used by KIOC[GS]RATE */
struct kbd_rate {
unsigned char delay; /* Delay in Hz before first repeat. */
unsigned char rate; /* In characters per second (0..50). */
};
/* Set keyboard rate */
#define KIOCSRATE _IOW('k', 40, struct kbd_rate)
/* Get keyboard rate */
#define KIOCGRATE _IOW('k', 41, struct kbd_rate)
/* Top bit records if the key is up or down */
#define KBD_UP 0x80
/* Usable information */
#define KBD_KEYMASK 0x7f
/* All keys up */
#define KBD_IDLE 0x75
#endif /* __LINUX_KBIO_H */
......@@ -38,15 +38,6 @@ struct sunos_ttysize {
int st_columns; /* Columns on the terminal */
};
/* Used for packet mode */
#define TIOCPKT_DATA 0
#define TIOCPKT_FLUSHREAD 1
#define TIOCPKT_FLUSHWRITE 2
#define TIOCPKT_STOP 4
#define TIOCPKT_START 8
#define TIOCPKT_NOSTOP 16
#define TIOCPKT_DOSTOP 32
struct winsize {
unsigned short ws_row;
unsigned short ws_col;
......
/* SunOS Virtual User Input Device (VUID) compatibility */
typedef struct firm_event {
unsigned short id; /* tag for this event */
unsigned char pair_type; /* unused by X11 */
unsigned char pair; /* unused by X11 */
int value; /* VKEY_UP, VKEY_DOWN or delta */
struct timeval time;
} Firm_event;
enum {
FE_PAIR_NONE,
FE_PAIR_SET,
FE_PAIR_DELTA,
FE_PAIR_ABSOLUTE
};
/* VUID stream formats */
#define VUID_NATIVE 0 /* Native byte stream format */
#define VUID_FIRM_EVENT 1 /* send firm_event structures */
/* ioctls */
/* Set input device byte stream format (any of VUID_{NATIVE,FIRM_EVENT}) */
#define VUIDSFORMAT _IOW('v', 1, int)
/* Retrieve input device byte stream format */
#define VUIDGFORMAT _IOR('v', 2, int)
/* Possible tag values */
/* mouse buttons: */
#define MS_LEFT 0x7f20
#define MS_MIDDLE 0x7f21
#define MS_RIGHT 0x7f22
/* motion: */
#define LOC_X_DELTA 0x7f80
#define LOC_Y_DELTA 0x7f81
#define LOC_X_ABSOLUTE 0x7f82 /* X compat, unsupported */
#define LOC_Y_ABSOLUTE 0x7f83 /* X compat, unsupported */
#define VKEY_UP 0
#define VKEY_DOWN 1
/*
* include/asm-sparc/audioio.h
*
* Sparc Audio Midlayer
* Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
*/
#ifndef _AUDIOIO_H_
#define _AUDIOIO_H_
/*
* SunOS/Solaris /dev/audio interface
*/
#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
#include <linux/types.h>
#include <linux/time.h>
#include <linux/ioctl.h>
#endif
/*
* This structure contains state information for audio device IO streams.
*/
typedef struct audio_prinfo {
/*
* The following values describe the audio data encoding.
*/
unsigned int sample_rate; /* samples per second */
unsigned int channels; /* number of interleaved channels */
unsigned int precision; /* bit-width of each sample */
unsigned int encoding; /* data encoding method */
/*
* The following values control audio device configuration
*/
unsigned int gain; /* gain level: 0 - 255 */
unsigned int port; /* selected I/O port (see below) */
unsigned int avail_ports; /* available I/O ports (see below) */
unsigned int _xxx[2]; /* Reserved for future use */
unsigned int buffer_size; /* I/O buffer size */
/*
* The following values describe driver state
*/
unsigned int samples; /* number of samples converted */
unsigned int eof; /* End Of File counter (play only) */
unsigned char pause; /* non-zero for pause, zero to resume */
unsigned char error; /* non-zero if overflow/underflow */
unsigned char waiting; /* non-zero if a process wants access */
unsigned char balance; /* stereo channel balance */
unsigned short minordev;
/*
* The following values are read-only state flags
*/
unsigned char open; /* non-zero if open access permitted */
unsigned char active; /* non-zero if I/O is active */
} audio_prinfo_t;
/*
* This structure describes the current state of the audio device.
*/
typedef struct audio_info {
/*
* Per-stream information
*/
audio_prinfo_t play; /* output status information */
audio_prinfo_t record; /* input status information */
/*
* Per-unit/channel information
*/
unsigned int monitor_gain; /* input to output mix: 0 - 255 */
unsigned char output_muted; /* non-zero if output is muted */
unsigned char _xxx[3]; /* Reserved for future use */
unsigned int _yyy[3]; /* Reserved for future use */
} audio_info_t;
/*
* Audio encoding types
*/
#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */
#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */
#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */
#define AUDIO_ENCODING_LINEAR (3) /* Linear PCM encoding */
#define AUDIO_ENCODING_FLOAT (4) /* IEEE float (-1. <-> +1.) */
#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */
#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */
#define AUDIO_ENCODING_LINEARLE (106) /* Linear PCM LE encoding */
/*
* These ranges apply to record, play, and monitor gain values
*/
#define AUDIO_MIN_GAIN (0) /* minimum gain value */
#define AUDIO_MAX_GAIN (255) /* maximum gain value */
/*
* These values apply to the balance field to adjust channel gain values
*/
#define AUDIO_LEFT_BALANCE (0) /* left channel only */
#define AUDIO_MID_BALANCE (32) /* equal left/right channel */
#define AUDIO_RIGHT_BALANCE (64) /* right channel only */
#define AUDIO_BALANCE_SHIFT (3)
/*
* Generic minimum/maximum limits for number of channels, both modes
*/
#define AUDIO_MIN_PLAY_CHANNELS (1)
#define AUDIO_MAX_PLAY_CHANNELS (4)
#define AUDIO_MIN_REC_CHANNELS (1)
#define AUDIO_MAX_REC_CHANNELS (4)
/*
* Generic minimum/maximum limits for sample precision
*/
#define AUDIO_MIN_PLAY_PRECISION (8)
#define AUDIO_MAX_PLAY_PRECISION (32)
#define AUDIO_MIN_REC_PRECISION (8)
#define AUDIO_MAX_REC_PRECISION (32)
/*
* Define some convenient names for typical audio ports
*/
/*
* output ports (several may be enabled simultaneously)
*/
#define AUDIO_SPEAKER 0x01 /* output to built-in speaker */
#define AUDIO_HEADPHONE 0x02 /* output to headphone jack */
#define AUDIO_LINE_OUT 0x04 /* output to line out */
/*
* input ports (usually only one at a time)
*/
#define AUDIO_MICROPHONE 0x01 /* input from microphone */
#define AUDIO_LINE_IN 0x02 /* input from line in */
#define AUDIO_CD 0x04 /* input from on-board CD inputs */
#define AUDIO_INTERNAL_CD_IN AUDIO_CD /* input from internal CDROM */
#define AUDIO_ANALOG_LOOPBACK 0x40 /* input from output */
/*
* This macro initializes an audio_info structure to 'harmless' values.
* Note that (~0) might not be a harmless value for a flag that was
* a signed int.
*/
#define AUDIO_INITINFO(i) { \
unsigned int *__x__; \
for (__x__ = (unsigned int *)(i); \
(char *) __x__ < (((char *)(i)) + sizeof (audio_info_t)); \
*__x__++ = ~0); \
}
/*
* These allow testing for what the user wants to set
*/
#define AUD_INITVALUE (~0)
#define Modify(X) ((unsigned int)(X) != AUD_INITVALUE)
#define Modifys(X) ((X) != (unsigned short)AUD_INITVALUE)
#define Modifyc(X) ((X) != (unsigned char)AUD_INITVALUE)
/*
* Parameter for the AUDIO_GETDEV ioctl to determine current
* audio devices.
*/
#define MAX_AUDIO_DEV_LEN (16)
typedef struct audio_device {
char name[MAX_AUDIO_DEV_LEN];
char version[MAX_AUDIO_DEV_LEN];
char config[MAX_AUDIO_DEV_LEN];
} audio_device_t;
/*
* Ioctl calls for the audio device.
*/
/*
* AUDIO_GETINFO retrieves the current state of the audio device.
*
* AUDIO_SETINFO copies all fields of the audio_info structure whose
* values are not set to the initialized value (-1) to the device state.
* It performs an implicit AUDIO_GETINFO to return the new state of the
* device. Note that the record.samples and play.samples fields are set
* to the last value before the AUDIO_SETINFO took effect. This allows
* an application to reset the counters while atomically retrieving the
* last value.
*
* AUDIO_DRAIN suspends the calling process until the write buffers are
* empty.
*
* AUDIO_GETDEV returns a structure of type audio_device_t which contains
* three strings. The string "name" is a short identifying string (for
* example, the SBus Fcode name string), the string "version" identifies
* the current version of the device, and the "config" string identifies
* the specific configuration of the audio stream. All fields are
* device-dependent -- see the device specific manual pages for details.
*
* AUDIO_GETDEV_SUNOS returns a number which is an audio device defined
* herein (making it not too portable)
*
* AUDIO_FLUSH stops all playback and recording, clears all queued buffers,
* resets error counters, and restarts recording and playback as appropriate
* for the current sampling mode.
*/
#define AUDIO_GETINFO _IOR('A', 1, audio_info_t)
#define AUDIO_SETINFO _IOWR('A', 2, audio_info_t)
#define AUDIO_DRAIN _IO('A', 3)
#define AUDIO_GETDEV _IOR('A', 4, audio_device_t)
#define AUDIO_GETDEV_SUNOS _IOR('A', 4, int)
#define AUDIO_FLUSH _IO('A', 5)
/* Define possible audio hardware configurations for
* old SunOS-style AUDIO_GETDEV ioctl */
#define AUDIO_DEV_UNKNOWN (0) /* not defined */
#define AUDIO_DEV_AMD (1) /* audioamd device */
#define AUDIO_DEV_SPEAKERBOX (2) /* dbri device with speakerbox */
#define AUDIO_DEV_CODEC (3) /* dbri device (internal speaker) */
#define AUDIO_DEV_CS4231 (5) /* cs4231 device */
/*
* The following ioctl sets the audio device into an internal loopback mode,
* if the hardware supports this. The argument is TRUE to set loopback,
* FALSE to reset to normal operation. If the hardware does not support
* internal loopback, the ioctl should fail with EINVAL.
* Causes ADC data to be digitally mixed in and sent to the DAC.
*/
#define AUDIO_DIAG_LOOPBACK _IOW('A', 101, int)
#endif /* _AUDIOIO_H_ */
......@@ -79,6 +79,7 @@ extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
size_t len);
extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
extern struct linux_ebus *ebus_chain;
......
#ifndef __LINUX_KBIO_H
#define __LINUX_KBIO_H
/* Return keyboard type */
#define KIOCTYPE _IOR('k', 9, int)
/* Return Keyboard layout */
#define KIOCLAYOUT _IOR('k', 20, int)
enum {
TR_NONE,
TR_ASCII, /* keyboard is in regular state */
TR_EVENT, /* keystrokes sent as firm events */
TR_UNTRANS_EVENT /* EVENT+up and down+no translation */
};
/* Return the current keyboard translation */
#define KIOCGTRANS _IOR('k', 5, int)
/* Set the keyboard translation */
#define KIOCTRANS _IOW('k', 0, int)
/* Send a keyboard command */
#define KIOCCMD _IOW('k', 8, int)
/* Return if keystrokes are being sent to /dev/kbd */
/* Set routing of keystrokes to /dev/kbd */
#define KIOCSDIRECT _IOW('k', 10, int)
/* Set keyboard leds */
#define KIOCSLED _IOW('k', 14, unsigned char)
/* Get keyboard leds */
#define KIOCGLED _IOR('k', 15, unsigned char)
/* Used by KIOC[GS]RATE */
struct kbd_rate {
unsigned char delay; /* Delay in Hz before first repeat. */
unsigned char rate; /* In characters per second (0..50). */
};
/* Set keyboard rate */
#define KIOCSRATE _IOW('k', 40, struct kbd_rate)
/* Get keyboard rate */
#define KIOCGRATE _IOW('k', 41, struct kbd_rate)
/* Top bit records if the key is up or down */
#define KBD_UP 0x80
/* Usable information */
#define KBD_KEYMASK 0x7f
/* All keys up */
#define KBD_IDLE 0x75
#endif /* __LINUX_KBIO_H */
......@@ -87,37 +87,35 @@ extern void __flush_tlb_mm(unsigned long, unsigned long);
static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk)
{
unsigned long ctx_valid;
int cpu;
/* Note: page_table_lock is used here to serialize switch_mm
* and activate_mm, and their calls to get_new_mmu_context.
* This use of page_table_lock is unrelated to its other uses.
*/
spin_lock(&mm->page_table_lock);
if (CTX_VALID(mm->context))
ctx_valid = 1;
else
ctx_valid = 0;
ctx_valid = CTX_VALID(mm->context);
if (!ctx_valid)
get_new_mmu_context(mm);
spin_unlock(&mm->page_table_lock);
if (!ctx_valid || (old_mm != mm)) {
if (!ctx_valid)
get_new_mmu_context(mm);
load_secondary_context(mm);
reload_tlbmiss_state(tsk, mm);
}
{
int cpu = smp_processor_id();
/* Even if (mm == old_mm) we _must_ check
* the cpu_vm_mask. If we do not we could
* corrupt the TLB state because of how
* smp_flush_tlb_{page,range,mm} on sparc64
* and lazy tlb switches work. -DaveM
*/
if (!ctx_valid || !cpu_isset(cpu, mm->cpu_vm_mask)) {
cpu_set(cpu, mm->cpu_vm_mask);
__flush_tlb_mm(CTX_HWBITS(mm->context),
SECONDARY_CONTEXT);
}
/* Even if (mm == old_mm) we _must_ check
* the cpu_vm_mask. If we do not we could
* corrupt the TLB state because of how
* smp_flush_tlb_{page,range,mm} on sparc64
* and lazy tlb switches work. -DaveM
*/
cpu = smp_processor_id();
if (!ctx_valid || !cpu_isset(cpu, mm->cpu_vm_mask)) {
cpu_set(cpu, mm->cpu_vm_mask);
__flush_tlb_mm(CTX_HWBITS(mm->context),
SECONDARY_CONTEXT);
}
spin_unlock(&mm->page_table_lock);
}
#define deactivate_mm(tsk,mm) do { } while (0)
......@@ -127,6 +125,10 @@ static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm
{
int cpu;
/* Note: page_table_lock is used here to serialize switch_mm
* and activate_mm, and their calls to get_new_mmu_context.
* This use of page_table_lock is unrelated to its other uses.
*/
spin_lock(&mm->page_table_lock);
if (!CTX_VALID(mm->context))
get_new_mmu_context(mm);
......
......@@ -38,15 +38,6 @@ struct sunos_ttysize {
int st_columns; /* Columns on the terminal */
};
/* Used for packet mode */
#define TIOCPKT_DATA 0
#define TIOCPKT_FLUSHREAD 1
#define TIOCPKT_FLUSHWRITE 2
#define TIOCPKT_STOP 4
#define TIOCPKT_START 8
#define TIOCPKT_NOSTOP 16
#define TIOCPKT_DOSTOP 32
struct winsize {
unsigned short ws_row;
unsigned short ws_col;
......
......@@ -58,11 +58,9 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, unsigned i
static inline void tlb_flush_mmu(struct mmu_gather *mp)
{
if (mp->need_flush) {
free_pages_and_swap_cache(mp->pages, mp->pages_nr);
mp->pages_nr = 0;
mp->need_flush = 0;
if (!tlb_fast_mode(mp)) {
free_pages_and_swap_cache(mp->pages, mp->pages_nr);
mp->pages_nr = 0;
}
}
}
......@@ -78,11 +76,9 @@ static inline void tlb_finish_mmu(struct mmu_gather *mp, unsigned long start, un
{
tlb_flush_mmu(mp);
if (mp->fullmm) {
if (CTX_VALID(mp->mm->context))
do_flush_tlb_mm(mp->mm);
if (mp->fullmm)
mp->fullmm = 0;
} else
else
flush_tlb_pending();
/* keep the page table cache within bounds */
......@@ -93,11 +89,11 @@ static inline void tlb_finish_mmu(struct mmu_gather *mp, unsigned long start, un
static inline void tlb_remove_page(struct mmu_gather *mp, struct page *page)
{
mp->need_flush = 1;
if (tlb_fast_mode(mp)) {
free_page_and_swap_cache(page);
return;
}
mp->need_flush = 1;
mp->pages[mp->pages_nr++] = page;
if (mp->pages_nr >= FREE_PTE_NR)
tlb_flush_mmu(mp);
......
/* SunOS Virtual User Input Device (VUID) compatibility */
typedef struct firm_event {
unsigned short id; /* tag for this event */
unsigned char pair_type; /* unused by X11 */
unsigned char pair; /* unused by X11 */
int value; /* VKEY_UP, VKEY_DOWN or delta */
struct timeval time;
} Firm_event;
enum {
FE_PAIR_NONE,
FE_PAIR_SET,
FE_PAIR_DELTA,
FE_PAIR_ABSOLUTE
};
/* VUID stream formats */
#define VUID_NATIVE 0 /* Native byte stream format */
#define VUID_FIRM_EVENT 1 /* send firm_event structures */
/* ioctls */
/* Set input device byte stream format (any of VUID_{NATIVE,FIRM_EVENT}) */
#define VUIDSFORMAT _IOW('v', 1, int)
/* Retrieve input device byte stream format */
#define VUIDGFORMAT _IOR('v', 2, int)
/* Possible tag values */
/* mouse buttons: */
#define MS_LEFT 0x7f20
#define MS_MIDDLE 0x7f21
#define MS_RIGHT 0x7f22
/* motion: */
#define LOC_X_DELTA 0x7f80
#define LOC_Y_DELTA 0x7f81
#define LOC_X_ABSOLUTE 0x7f82 /* X compat, unsupported */
#define LOC_Y_ABSOLUTE 0x7f83 /* X compat, unsupported */
#define VKEY_UP 0
#define VKEY_DOWN 1
......@@ -470,13 +470,6 @@ static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
if (clone_flags & CLONE_VM) {
atomic_inc(&oldmm->mm_users);
mm = oldmm;
/*
* There are cases where the PTL is held to ensure no
* new threads start up in user mode using an mm, which
* allows optimizing out ipis; the tlb_gather_mmu code
* is an example.
*/
spin_unlock_wait(&oldmm->page_table_lock);
goto good_mm;
}
......
......@@ -61,13 +61,37 @@ MODULE_DESCRIPTION("Sun CS4231");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}");
typedef struct snd_cs4231 {
spinlock_t lock;
void __iomem *port;
#ifdef SBUS_SUPPORT
typedef struct sbus_dma_info {
spinlock_t lock;
int dir;
void __iomem *regs;
} sbus_dma_info_t;
#endif
typedef struct snd_cs4231 cs4231_t;
typedef struct cs4231_dma_control {
void (*prepare)(struct cs4231_dma_control *dma_cont, int dir);
void (*enable)(struct cs4231_dma_control *dma_cont, int on);
int (*request)(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len);
unsigned int (*address)(struct cs4231_dma_control *dma_cont);
void (*reset)(cs4231_t *chip);
void (*preallocate)(cs4231_t *chip, snd_pcm_t *pcm);
#ifdef EBUS_SUPPORT
struct ebus_dma_info eb2c;
struct ebus_dma_info eb2p;
struct ebus_dma_info ebus_info;
#endif
#ifdef SBUS_SUPPORT
struct sbus_dma_info sbus_info;
#endif
} cs4231_dma_control_t;
struct snd_cs4231 {
spinlock_t lock;
void __iomem *port;
cs4231_dma_control_t p_dma;
cs4231_dma_control_t c_dma;
u32 flags;
#define CS4231_FLAG_EBUS 0x00000001
......@@ -106,7 +130,7 @@ typedef struct snd_cs4231 {
unsigned int irq[2];
unsigned int regs_size;
struct snd_cs4231 *next;
} cs4231_t;
};
static cs4231_t *cs4231_list;
......@@ -251,6 +275,15 @@ static cs4231_t *cs4231_list;
#define APCPNVA 0x38UL /* APC Play DMA Next Address */
#define APCPNC 0x3cUL /* APC Play Next Count */
/* Defines for SBUS DMA-routines */
#define APCVA 0x0UL /* APC DMA Address */
#define APCC 0x4UL /* APC Count */
#define APCNVA 0x8UL /* APC DMA Next Address */
#define APCNC 0xcUL /* APC Next Count */
#define APC_PLAY 0x30UL /* Play registers start at 0x30 */
#define APC_RECORD 0x20UL /* Record registers start at 0x20 */
/* APCCSR bits */
#define APC_INT_PENDING 0x800000 /* Interrupt Pending */
......@@ -569,8 +602,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
spin_unlock_irqrestore(&chip->lock, flags);
}
#ifdef EBUS_SUPPORT
static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent)
static void snd_cs4231_advance_dma(struct cs4231_dma_control *dma_cont, snd_pcm_substream_t *substream, unsigned int *periods_sent)
{
snd_pcm_runtime_t *runtime = substream->runtime;
......@@ -581,129 +613,41 @@ static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substre
if (period_size >= (1 << 24))
BUG();
if (ebus_dma_request(p, runtime->dma_addr + offset, period_size))
if (dma_cont->request(dma_cont, runtime->dma_addr + offset, period_size))
return;
(*periods_sent) = ((*periods_sent) + 1) % runtime->periods;
}
}
#endif
#ifdef SBUS_SUPPORT
static void snd_cs4231_sbus_advance_dma(snd_pcm_substream_t *substream, unsigned int *periods_sent)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned int period_size = snd_pcm_lib_period_bytes(substream);
unsigned int offset = period_size * (*periods_sent % runtime->periods);
if (runtime->period_size > 0xffff + 1)
BUG();
switch (substream->stream) {
case SNDRV_PCM_STREAM_PLAYBACK:
sbus_writel(runtime->dma_addr + offset, chip->port + APCPNVA);
sbus_writel(period_size, chip->port + APCPNC);
break;
case SNDRV_PCM_STREAM_CAPTURE:
sbus_writel(runtime->dma_addr + offset, chip->port + APCCNVA);
sbus_writel(period_size, chip->port + APCCNC);
break;
}
(*periods_sent) = (*periods_sent + 1) % runtime->periods;
}
#endif
static void cs4231_dma_trigger(snd_pcm_substream_t *substream, unsigned int what, int on)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
cs4231_dma_control_t *dma_cont;
#ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) {
if (what & CS4231_PLAYBACK_ENABLE) {
if (on) {
ebus_dma_prepare(&chip->eb2p, 0);
ebus_dma_enable(&chip->eb2p, 1);
snd_cs4231_ebus_advance_dma(&chip->eb2p,
chip->playback_substream,
&chip->p_periods_sent);
} else {
ebus_dma_enable(&chip->eb2p, 0);
}
}
if (what & CS4231_RECORD_ENABLE) {
if (on) {
ebus_dma_prepare(&chip->eb2c, 1);
ebus_dma_enable(&chip->eb2c, 1);
snd_cs4231_ebus_advance_dma(&chip->eb2c,
chip->capture_substream,
&chip->c_periods_sent);
} else {
ebus_dma_enable(&chip->eb2c, 0);
}
}
} else {
#endif
#ifdef SBUS_SUPPORT
u32 csr = sbus_readl(chip->port + APCCSR);
/* I don't know why, but on sbus the period counter must
* only start counting after the first period is sent.
* Therefore this dummy thing.
*/
unsigned int dummy = 0;
switch (what) {
case CS4231_PLAYBACK_ENABLE:
if (what & CS4231_PLAYBACK_ENABLE) {
dma_cont = &chip->p_dma;
if (on) {
csr &= ~APC_XINT_PLAY;
sbus_writel(csr, chip->port + APCCSR);
csr &= ~APC_PPAUSE;
sbus_writel(csr, chip->port + APCCSR);
snd_cs4231_sbus_advance_dma(substream, &dummy);
csr |= APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA |
APC_XINT_PLAY | APC_XINT_EMPT | APC_XINT_GENL |
APC_XINT_PENA | APC_PDMA_READY;
sbus_writel(csr, chip->port + APCCSR);
dma_cont->prepare(dma_cont, 0);
dma_cont->enable(dma_cont, 1);
snd_cs4231_advance_dma(dma_cont,
chip->playback_substream,
&chip->p_periods_sent);
} else {
csr |= APC_PPAUSE;
sbus_writel(csr, chip->port + APCCSR);
csr &= ~APC_PDMA_READY;
sbus_writel(csr, chip->port + APCCSR);
dma_cont->enable(dma_cont, 0);
}
break;
case CS4231_RECORD_ENABLE:
}
if (what & CS4231_RECORD_ENABLE) {
dma_cont = &chip->c_dma;
if (on) {
csr &= ~APC_XINT_CAPT;
sbus_writel(csr, chip->port + APCCSR);
csr &= ~APC_CPAUSE;
sbus_writel(csr, chip->port + APCCSR);
snd_cs4231_sbus_advance_dma(substream, &dummy);
csr |= APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA |
APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL |
APC_CDMA_READY;
sbus_writel(csr, chip->port + APCCSR);
dma_cont->prepare(dma_cont, 1);
dma_cont->enable(dma_cont, 1);
snd_cs4231_advance_dma(dma_cont,
chip->capture_substream,
&chip->c_periods_sent);
} else {
csr |= APC_CPAUSE;
sbus_writel(csr, chip->port + APCCSR);
csr &= ~APC_CDMA_READY;
sbus_writel(csr, chip->port + APCCSR);
dma_cont->enable(dma_cont, 0);
}
break;
}
#endif
#ifdef EBUS_SUPPORT
}
#endif
}
static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
......@@ -1136,10 +1080,7 @@ static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream)
if (runtime->period_size > 0xffff + 1)
BUG();
snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (runtime->period_size - 1) & 0x00ff);
snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff);
chip->p_periods_sent = 0;
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
......@@ -1171,16 +1112,14 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream)
static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |
CS4231_RECORD_PIO);
snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) & 0x00ff);
snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff);
chip->c_periods_sent = 0;
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
......@@ -1199,134 +1138,55 @@ static void snd_cs4231_overrange(cs4231_t *chip)
chip->capture_substream->runtime->overrange++;
}
static irqreturn_t snd_cs4231_generic_interrupt(cs4231_t *chip)
{
unsigned long flags;
unsigned char status;
/*This is IRQ is not raised by the cs4231*/
if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ))
return IRQ_NONE;
status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
if (status & CS4231_TIMER_IRQ) {
if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
}
if (status & CS4231_RECORD_IRQ)
snd_cs4231_overrange(chip);
/* ACK the CS4231 interrupt. */
spin_lock_irqsave(&chip->lock, flags);
snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
#ifdef SBUS_SUPPORT
static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
cs4231_t *chip = dev_id;
/* ACK the APC interrupt. */
u32 csr = sbus_readl(chip->port + APCCSR);
sbus_writel(csr, chip->port + APCCSR);
if ((chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) &&
(csr & APC_PLAY_INT) &&
(csr & APC_XINT_PNVA) &&
!(csr & APC_XINT_EMPT)) {
snd_cs4231_sbus_advance_dma(chip->playback_substream,
&chip->p_periods_sent);
snd_pcm_period_elapsed(chip->playback_substream);
}
if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) &&
(csr & APC_CAPT_INT) &&
(csr & APC_XINT_CNVA)) {
snd_cs4231_sbus_advance_dma(chip->capture_substream,
&chip->c_periods_sent);
snd_pcm_period_elapsed(chip->capture_substream);
}
return snd_cs4231_generic_interrupt(chip);
}
#endif
#ifdef EBUS_SUPPORT
static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie)
static void snd_cs4231_play_callback(cs4231_t *cookie)
{
cs4231_t *chip = cookie;
if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) {
snd_pcm_period_elapsed(chip->playback_substream);
snd_cs4231_ebus_advance_dma(p, chip->playback_substream,
snd_cs4231_advance_dma(&chip->p_dma, chip->playback_substream,
&chip->p_periods_sent);
}
}
static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie)
static void snd_cs4231_capture_callback(cs4231_t *cookie)
{
cs4231_t *chip = cookie;
if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) {
snd_pcm_period_elapsed(chip->capture_substream);
snd_cs4231_ebus_advance_dma(p, chip->capture_substream,
snd_cs4231_advance_dma(&chip->c_dma, chip->capture_substream,
&chip->c_periods_sent);
}
}
#endif
static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
size_t ptr, residue, period_bytes;
cs4231_dma_control_t *dma_cont = &chip->p_dma;
size_t ptr;
if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
return 0;
period_bytes = snd_pcm_lib_period_bytes(substream);
ptr = period_bytes * chip->p_periods_sent;
#ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) {
residue = ebus_dma_residue(&chip->eb2p);
} else {
#endif
#ifdef SBUS_SUPPORT
residue = sbus_readl(chip->port + APCPC);
#endif
#ifdef EBUS_SUPPORT
}
#endif
ptr += period_bytes - residue;
ptr = dma_cont->address(dma_cont);
if (ptr != 0)
ptr -= substream->runtime->dma_addr;
return bytes_to_frames(substream->runtime, ptr);
}
static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
size_t ptr, residue, period_bytes;
cs4231_dma_control_t *dma_cont = &chip->c_dma;
size_t ptr;
if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
return 0;
period_bytes = snd_pcm_lib_period_bytes(substream);
ptr = period_bytes * chip->c_periods_sent;
#ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) {
residue = ebus_dma_residue(&chip->eb2c);
} else {
#endif
#ifdef SBUS_SUPPORT
residue = sbus_readl(chip->port + APCCC);
#endif
#ifdef EBUS_SUPPORT
}
#endif
ptr += period_bytes - residue;
ptr = dma_cont->address(dma_cont);
if (ptr != 0)
ptr -= substream->runtime->dma_addr;
return bytes_to_frames(substream->runtime, ptr);
}
......@@ -1362,30 +1222,8 @@ static int snd_cs4231_probe(cs4231_t *chip)
spin_lock_irqsave(&chip->lock, flags);
/* Reset DMA engine. */
#ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) {
/* Done by ebus_dma_register */
} else {
#endif
#ifdef SBUS_SUPPORT
sbus_writel(APC_CHIP_RESET, chip->port + APCCSR);
sbus_writel(0x00, chip->port + APCCSR);
sbus_writel(sbus_readl(chip->port + APCCSR) | APC_CDC_RESET,
chip->port + APCCSR);
udelay(20);
sbus_writel(sbus_readl(chip->port + APCCSR) & ~APC_CDC_RESET,
chip->port + APCCSR);
sbus_writel(sbus_readl(chip->port + APCCSR) | (APC_XINT_ENA |
APC_XINT_PENA |
APC_XINT_CENA),
chip->port + APCCSR);
#endif
#ifdef EBUS_SUPPORT
}
#endif
/* Reset DMA engine (sbus only). */
chip->p_dma.reset(chip);
__cs4231_readb(chip, CS4231P(chip, STATUS)); /* clear any pendings IRQ */
__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));
......@@ -1505,8 +1343,8 @@ static int snd_cs4231_playback_close(snd_pcm_substream_t *substream)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
chip->playback_substream = NULL;
snd_cs4231_close(chip, CS4231_MODE_PLAY);
chip->playback_substream = NULL;
return 0;
}
......@@ -1515,8 +1353,8 @@ static int snd_cs4231_capture_close(snd_pcm_substream_t *substream)
{
cs4231_t *chip = snd_pcm_substream_chip(substream);
chip->capture_substream = NULL;
snd_cs4231_close(chip, CS4231_MODE_RECORD);
chip->capture_substream = NULL;
return 0;
}
......@@ -1571,21 +1409,7 @@ int snd_cs4231_pcm(cs4231_t *chip)
pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
strcpy(pcm->name, "CS4231");
#ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) {
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->dev_u.pdev),
64*1024, 128*1024);
} else {
#endif
#ifdef SBUS_SUPPORT
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
snd_dma_sbus_data(chip->dev_u.sdev),
64*1024, 128*1024);
#endif
#ifdef EBUS_SUPPORT
}
#endif
chip->p_dma.preallocate(chip, pcm);
chip->pcm = pcm;
......@@ -1942,6 +1766,180 @@ static int cs4231_attach_finish(snd_card_t *card, cs4231_t *chip)
}
#ifdef SBUS_SUPPORT
static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
unsigned char status;
u32 csr;
cs4231_t *chip = dev_id;
/*This is IRQ is not raised by the cs4231*/
if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ))
return IRQ_NONE;
/* ACK the APC interrupt. */
csr = sbus_readl(chip->port + APCCSR);
sbus_writel(csr, chip->port + APCCSR);
if ((csr & APC_PDMA_READY) &&
(csr & APC_PLAY_INT) &&
(csr & APC_XINT_PNVA) &&
!(csr & APC_XINT_EMPT))
snd_cs4231_play_callback(chip);
if ((csr & APC_CDMA_READY) &&
(csr & APC_CAPT_INT) &&
(csr & APC_XINT_CNVA) &&
!(csr & APC_XINT_EMPT))
snd_cs4231_capture_callback(chip);
status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
if (status & CS4231_TIMER_IRQ) {
if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
}
if ((status & CS4231_RECORD_IRQ) && (csr & APC_CDMA_READY))
snd_cs4231_overrange(chip);
/* ACK the CS4231 interrupt. */
spin_lock_irqsave(&chip->lock, flags);
snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
/*
* SBUS DMA routines
*/
int sbus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len)
{
unsigned long flags;
u32 test, csr;
int err;
sbus_dma_info_t *base = &dma_cont->sbus_info;
if (len >= (1 << 24))
return -EINVAL;
spin_lock_irqsave(&base->lock, flags);
csr = sbus_readl(base->regs + APCCSR);
err = -EINVAL;
test = APC_CDMA_READY;
if ( base->dir == APC_PLAY )
test = APC_PDMA_READY;
if (!(csr & test))
goto out;
err = -EBUSY;
csr = sbus_readl(base->regs + APCCSR);
test = APC_XINT_CNVA;
if ( base->dir == APC_PLAY )
test = APC_XINT_PNVA;
if (!(csr & test))
goto out;
err = 0;
sbus_writel(bus_addr, base->regs + base->dir + APCNVA);
sbus_writel(len, base->regs + base->dir + APCNC);
out:
spin_unlock_irqrestore(&base->lock, flags);
return err;
}
void sbus_dma_prepare(struct cs4231_dma_control *dma_cont, int d)
{
unsigned long flags;
u32 csr, test;
sbus_dma_info_t *base = &dma_cont->sbus_info;
spin_lock_irqsave(&base->lock, flags);
csr = sbus_readl(base->regs + APCCSR);
test = APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA |
APC_XINT_PLAY | APC_XINT_PEMP | APC_XINT_GENL |
APC_XINT_PENA;
if ( base->dir == APC_RECORD )
test = APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA |
APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL;
csr |= test;
sbus_writel(csr, base->regs + APCCSR);
spin_unlock_irqrestore(&base->lock, flags);
}
void sbus_dma_enable(struct cs4231_dma_control *dma_cont, int on)
{
unsigned long flags;
u32 csr, shift;
sbus_dma_info_t *base = &dma_cont->sbus_info;
spin_lock_irqsave(&base->lock, flags);
if (!on) {
if (base->dir == APC_PLAY) {
sbus_writel(0, base->regs + base->dir + APCNVA);
sbus_writel(1, base->regs + base->dir + APCC);
}
else
{
sbus_writel(0, base->regs + base->dir + APCNC);
sbus_writel(0, base->regs + base->dir + APCVA);
}
}
udelay(600);
csr = sbus_readl(base->regs + APCCSR);
shift = 0;
if ( base->dir == APC_PLAY )
shift = 1;
if (on)
csr &= ~(APC_CPAUSE << shift);
else
csr |= (APC_CPAUSE << shift);
sbus_writel(csr, base->regs + APCCSR);
if (on)
csr |= (APC_CDMA_READY << shift);
else
csr &= ~(APC_CDMA_READY << shift);
sbus_writel(csr, base->regs + APCCSR);
spin_unlock_irqrestore(&base->lock, flags);
}
unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont)
{
sbus_dma_info_t *base = &dma_cont->sbus_info;
return sbus_readl(base->regs + base->dir + APCVA);
}
void sbus_dma_reset(cs4231_t *chip)
{
sbus_writel(APC_CHIP_RESET, chip->port + APCCSR);
sbus_writel(0x00, chip->port + APCCSR);
sbus_writel(sbus_readl(chip->port + APCCSR) | APC_CDC_RESET,
chip->port + APCCSR);
udelay(20);
sbus_writel(sbus_readl(chip->port + APCCSR) & ~APC_CDC_RESET,
chip->port + APCCSR);
sbus_writel(sbus_readl(chip->port + APCCSR) | (APC_XINT_ENA |
APC_XINT_PENA |
APC_XINT_CENA),
chip->port + APCCSR);
}
void sbus_dma_preallocate(cs4231_t *chip, snd_pcm_t *pcm)
{
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
snd_dma_sbus_data(chip->dev_u.sdev),
64*1024, 128*1024);
}
/*
* Init and exit routines
*/
static int snd_cs4231_sbus_free(cs4231_t *chip)
{
if (chip->irq[0])
......@@ -1983,6 +1981,8 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card,
return -ENOMEM;
spin_lock_init(&chip->lock);
spin_lock_init(&chip->c_dma.sbus_info.lock);
spin_lock_init(&chip->p_dma.sbus_info.lock);
init_MUTEX(&chip->mce_mutex);
init_MUTEX(&chip->open_mutex);
chip->card = card;
......@@ -1998,6 +1998,25 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card,
return -EIO;
}
chip->c_dma.sbus_info.regs = chip->port;
chip->p_dma.sbus_info.regs = chip->port;
chip->c_dma.sbus_info.dir = APC_RECORD;
chip->p_dma.sbus_info.dir = APC_PLAY;
chip->p_dma.prepare = sbus_dma_prepare;
chip->p_dma.enable = sbus_dma_enable;
chip->p_dma.request = sbus_dma_request;
chip->p_dma.address = sbus_dma_addr;
chip->p_dma.reset = sbus_dma_reset;
chip->p_dma.preallocate = sbus_dma_preallocate;
chip->c_dma.prepare = sbus_dma_prepare;
chip->c_dma.enable = sbus_dma_enable;
chip->c_dma.request = sbus_dma_request;
chip->c_dma.address = sbus_dma_addr;
chip->c_dma.reset = sbus_dma_reset;
chip->c_dma.preallocate = sbus_dma_preallocate;
if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
SA_SHIRQ, "cs4231", chip)) {
snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n",
......@@ -2051,15 +2070,70 @@ static int cs4231_sbus_attach(struct sbus_dev *sdev)
#endif
#ifdef EBUS_SUPPORT
static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie)
{
cs4231_t *chip = cookie;
snd_cs4231_play_callback(chip);
}
static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie)
{
cs4231_t *chip = cookie;
snd_cs4231_capture_callback(chip);
}
/*
* EBUS DMA wrappers
*/
int _ebus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len)
{
return ebus_dma_request(&dma_cont->ebus_info, bus_addr, len);
}
void _ebus_dma_enable(struct cs4231_dma_control *dma_cont, int on)
{
ebus_dma_enable(&dma_cont->ebus_info, on);
}
void _ebus_dma_prepare(struct cs4231_dma_control *dma_cont, int dir)
{
ebus_dma_prepare(&dma_cont->ebus_info, dir);
}
unsigned int _ebus_dma_addr(struct cs4231_dma_control *dma_cont)
{
return ebus_dma_addr(&dma_cont->ebus_info);
}
void _ebus_dma_reset(cs4231_t *chip)
{
return;
}
void _ebus_dma_preallocate(cs4231_t *chip, snd_pcm_t *pcm)
{
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->dev_u.pdev),
64*1024, 128*1024);
}
/*
* Init and exit routines
*/
static int snd_cs4231_ebus_free(cs4231_t *chip)
{
if (chip->eb2c.regs) {
ebus_dma_unregister(&chip->eb2c);
iounmap(chip->eb2c.regs);
if (chip->c_dma.ebus_info.regs) {
ebus_dma_unregister(&chip->c_dma.ebus_info);
iounmap(chip->c_dma.ebus_info.regs);
}
if (chip->eb2p.regs) {
ebus_dma_unregister(&chip->eb2p);
iounmap(chip->eb2p.regs);
if (chip->p_dma.ebus_info.regs) {
ebus_dma_unregister(&chip->p_dma.ebus_info);
iounmap(chip->p_dma.ebus_info.regs);
}
if (chip->port)
......@@ -2097,8 +2171,8 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card,
return -ENOMEM;
spin_lock_init(&chip->lock);
spin_lock_init(&chip->eb2c.lock);
spin_lock_init(&chip->eb2p.lock);
spin_lock_init(&chip->c_dma.ebus_info.lock);
spin_lock_init(&chip->p_dma.ebus_info.lock);
init_MUTEX(&chip->mce_mutex);
init_MUTEX(&chip->open_mutex);
chip->flags |= CS4231_FLAG_EBUS;
......@@ -2106,43 +2180,57 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card,
chip->dev_u.pdev = edev->bus->self;
memcpy(&chip->image, &snd_cs4231_original_image,
sizeof(snd_cs4231_original_image));
strcpy(chip->eb2c.name, "cs4231(capture)");
chip->eb2c.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->eb2c.callback = snd_cs4231_ebus_capture_callback;
chip->eb2c.client_cookie = chip;
chip->eb2c.irq = edev->irqs[0];
strcpy(chip->eb2p.name, "cs4231(play)");
chip->eb2p.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->eb2p.callback = snd_cs4231_ebus_play_callback;
chip->eb2p.client_cookie = chip;
chip->eb2p.irq = edev->irqs[1];
strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)");
chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback;
chip->c_dma.ebus_info.client_cookie = chip;
chip->c_dma.ebus_info.irq = edev->irqs[0];
strcpy(chip->p_dma.ebus_info.name, "cs4231(play)");
chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback;
chip->p_dma.ebus_info.client_cookie = chip;
chip->p_dma.ebus_info.irq = edev->irqs[1];
chip->p_dma.prepare = _ebus_dma_prepare;
chip->p_dma.enable = _ebus_dma_enable;
chip->p_dma.request = _ebus_dma_request;
chip->p_dma.address = _ebus_dma_addr;
chip->p_dma.reset = _ebus_dma_reset;
chip->p_dma.preallocate = _ebus_dma_preallocate;
chip->c_dma.prepare = _ebus_dma_prepare;
chip->c_dma.enable = _ebus_dma_enable;
chip->c_dma.request = _ebus_dma_request;
chip->c_dma.address = _ebus_dma_addr;
chip->c_dma.reset = _ebus_dma_reset;
chip->c_dma.preallocate = _ebus_dma_preallocate;
chip->port = ioremap(edev->resource[0].start, 0x10);
chip->eb2p.regs = ioremap(edev->resource[1].start, 0x10);
chip->eb2c.regs = ioremap(edev->resource[2].start, 0x10);
if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) {
chip->p_dma.ebus_info.regs = ioremap(edev->resource[1].start, 0x10);
chip->c_dma.ebus_info.regs = ioremap(edev->resource[2].start, 0x10);
if (!chip->port || !chip->p_dma.ebus_info.regs || !chip->c_dma.ebus_info.regs) {
snd_cs4231_ebus_free(chip);
snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
return -EIO;
}
if (ebus_dma_register(&chip->eb2c)) {
if (ebus_dma_register(&chip->c_dma.ebus_info)) {
snd_cs4231_ebus_free(chip);
snd_printdd("cs4231-%d: Unable to register EBUS capture DMA\n", dev);
return -EBUSY;
}
if (ebus_dma_irq_enable(&chip->eb2c, 1)) {
if (ebus_dma_irq_enable(&chip->c_dma.ebus_info, 1)) {
snd_cs4231_ebus_free(chip);
snd_printdd("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev);
return -EBUSY;
}
if (ebus_dma_register(&chip->eb2p)) {
if (ebus_dma_register(&chip->p_dma.ebus_info)) {
snd_cs4231_ebus_free(chip);
snd_printdd("cs4231-%d: Unable to register EBUS play DMA\n", dev);
return -EBUSY;
}
if (ebus_dma_irq_enable(&chip->eb2p, 1)) {
if (ebus_dma_irq_enable(&chip->p_dma.ebus_info, 1)) {
snd_cs4231_ebus_free(chip);
snd_printdd("cs4231-%d: Unable to enable EBUS play IRQ\n", dev);
return -EBUSY;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment