The last patch in alsa-driver/utils/patches is for 2.4.16 and doesn't apply cleanly to newer kernels.
diff -ur linux/drivers/char/Makefile linux-2.4.20/drivers/char/Makefile --- linux/drivers/char/Makefile Sun Jan 25 14:01:48 2004 +++ linux-2.4.20/drivers/char/Makefile Sun Jan 25 13:59:13 2004 @@ -23,7 +23,7 @@ export-objs := busmouse.o console.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o \ - sonypi.o tty_io.o tty_ioctl.o generic_serial.o \ + sonypi.o tty_io.o tty_ioctl.o generic_serial.o rtc.o \ au1000_gpio.o hp_psaux.o nvram.o mod-subdirs := joystick ftape drm drm-4.0 pcmcia diff -ur linux/drivers/char/rtc.c linux-2.4.20/drivers/char/rtc.c --- linux/drivers/char/rtc.c Sun Jan 25 14:05:51 2004 +++ linux-2.4.20/drivers/char/rtc.c Sun Jan 25 14:08:22 2004 @@ -141,6 +141,11 @@ static unsigned long rtc_irq_data = 0; /* our output to the world */ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ +#if RTC_IRQ +static spinlock_t rtc_task_lock = SPIN_LOCK_UNLOCKED; +static rtc_task_t *rtc_callback = NULL; +#endif + /* * If this driver ever becomes modularised, it will be really nice * to make the epoch retain its value across module reload... @@ -182,6 +187,10 @@ spin_unlock (&rtc_lock); /* Now do the rest of the actions */ + spin_lock(&rtc_task_lock); + if (rtc_callback) + rtc_callback->func(rtc_callback->private_data); + spin_unlock(&rtc_task_lock); wake_up_interruptible(&rtc_wait); kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); @@ -278,8 +287,7 @@ #endif } -static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) { struct rtc_time wtime; @@ -329,7 +337,7 @@ * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. */ - if ((rtc_freq > rtc_max_user_freq) && + if (!kernel && (rtc_freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) return -EACCES; @@ -528,7 +536,8 @@ * We don't really want Joe User generating more * than 64Hz of interrupts on a multi-user machine. */ - if ((arg > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) + if (!kernel && (arg > rtc_max_user_freq) && + (!capable(CAP_SYS_RESOURCE))) return -EACCES; while (arg > (1<<tmp)) @@ -574,6 +583,12 @@ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; } +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + return rtc_do_ioctl(cmd, arg, 0); +} + /* * We enforce only one user at a time here with the open/close. * Also clear the previous interrupt data on an open, and clean @@ -641,11 +656,8 @@ spin_lock_irq (&rtc_lock); rtc_irq_data = 0; - spin_unlock_irq (&rtc_lock); - - /* No need for locking -- nobody else can do anything until this rmw is - * committed, and no timer is running. */ rtc_status &= ~RTC_IS_OPEN; + spin_unlock_irq (&rtc_lock); return 0; } @@ -671,6 +683,88 @@ #endif /* + * exported stuff + */ + +EXPORT_SYMBOL(rtc_register); +EXPORT_SYMBOL(rtc_unregister); +EXPORT_SYMBOL(rtc_control); + +int rtc_register(rtc_task_t *task) +{ +#if !RTC_IRQ + return -EIO; +#else + if (task == NULL || task->func == NULL) + return -EINVAL; + spin_lock_irq(&rtc_lock); + if (rtc_status & RTC_IS_OPEN) { + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + spin_lock(&rtc_task_lock); + if (rtc_callback) { + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + rtc_status |= RTC_IS_OPEN; + rtc_callback = task; + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return 0; +#endif +} + +int rtc_unregister(rtc_task_t *task) +{ +#if !RTC_IRQ + return -EIO; +#else + unsigned char tmp; + + spin_lock_irq(&rtc_task_lock); + if (rtc_callback != task) { + spin_unlock_irq(&rtc_task_lock); + return -ENXIO; + } + rtc_callback = NULL; + spin_lock(&rtc_lock); + /* disable controls */ + tmp = CMOS_READ(RTC_CONTROL); + tmp &= ~RTC_PIE; + tmp &= ~RTC_AIE; + tmp &= ~RTC_UIE; + CMOS_WRITE(tmp, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + if (rtc_status & RTC_TIMER_ON) { + rtc_status &= ~RTC_TIMER_ON; + del_timer(&rtc_irq_timer); + } + rtc_status &= ~RTC_IS_OPEN; + spin_unlock(&rtc_lock); + spin_unlock_irq(&rtc_task_lock); + return 0; +#endif +} + +int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) +{ +#if !RTC_IRQ + return -EIO; +#else + spin_lock_irq(&rtc_task_lock); + if (rtc_callback != task) { + spin_unlock_irq(&rtc_task_lock); + return -ENXIO; + } + spin_unlock_irq(&rtc_task_lock); + return rtc_do_ioctl(cmd, arg, 1); +#endif +} + + +/* * The various file operations we support. */ @@ -860,7 +954,6 @@ module_init(rtc_init); module_exit(rtc_exit); -EXPORT_NO_SYMBOLS; #if RTC_IRQ /* diff -ur linux/include/linux/rtc.h linux-2.4.20/include/linux/rtc.h --- linux/include/linux/rtc.h Sun Jan 25 14:01:22 2004 +++ linux-2.4.20/include/linux/rtc.h Sun Jan 25 13:58:57 2004 @@ -66,4 +66,17 @@ #define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/ #define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/ +/* Exported functions to other kernel drivers */ + +#ifdef __KERNEL__ +typedef struct rtc_task { + void (*func)(void *private_data); + void *private_data; +} rtc_task_t; + +int rtc_register(rtc_task_t *task); +int rtc_unregister(rtc_task_t *task); +int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg); +#endif + #endif /* _LINUX_RTC_H_ */
diff -ur linux/drivers/char/Makefile linux-2.4.23/drivers/char/Makefile --- linux/drivers/char/Makefile Thu Jan 15 14:34:08 2004 +++ linux-2.4.23/drivers/char/Makefile Thu Jan 15 14:33:01 2004 @@ -23,7 +23,7 @@ export-objs := busmouse.o console.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o \ - sonypi.o tty_io.o tty_ioctl.o generic_serial.o \ + sonypi.o tty_io.o tty_ioctl.o generic_serial.o rtc.o \ au1000_gpio.o hp_psaux.o nvram.o scx200.o fetchop.o mod-subdirs := joystick ftape drm drm-4.0 pcmcia diff -ur linux/drivers/char/rtc.c linux-2.4.23/drivers/char/rtc.c --- linux/drivers/char/rtc.c Sat Jan 24 12:06:07 2004 +++ linux-2.4.23/drivers/char/rtc.c Fri Jan 16 23:22:39 2004 @@ -142,6 +142,11 @@ static unsigned long rtc_irq_data = 0; /* our output to the world */ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ +#if RTC_IRQ +static spinlock_t rtc_task_lock = SPIN_LOCK_UNLOCKED; +static rtc_task_t *rtc_callback = NULL; +#endif + /* * If this driver ever becomes modularised, it will be really nice * to make the epoch retain its value across module reload... @@ -183,6 +188,10 @@ spin_unlock (&rtc_lock); /* Now do the rest of the actions */ + spin_lock(&rtc_task_lock); + if (rtc_callback) + rtc_callback->func(rtc_callback->private_data); + spin_unlock(&rtc_task_lock); wake_up_interruptible(&rtc_wait); kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); @@ -279,8 +288,7 @@ #endif } -static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) { struct rtc_time wtime; @@ -330,7 +338,7 @@ * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. */ - if ((rtc_freq > rtc_max_user_freq) && + if (!kernel && (rtc_freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) return -EACCES; @@ -526,7 +534,8 @@ * We don't really want Joe User generating more * than 64Hz of interrupts on a multi-user machine. */ - if ((arg > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) + if (!kernel && (arg > rtc_max_user_freq) && + (!capable(CAP_SYS_RESOURCE))) return -EACCES; while (arg > (1<<tmp)) @@ -572,6 +581,12 @@ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; } +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + return rtc_do_ioctl(cmd, arg, 0); +} + /* * We enforce only one user at a time here with the open/close. * Also clear the previous interrupt data on an open, and clean @@ -639,11 +654,8 @@ spin_lock_irq (&rtc_lock); rtc_irq_data = 0; - spin_unlock_irq (&rtc_lock); - - /* No need for locking -- nobody else can do anything until this rmw is - * committed, and no timer is running. */ rtc_status &= ~RTC_IS_OPEN; + spin_unlock_irq (&rtc_lock); return 0; } @@ -669,6 +681,88 @@ #endif /* + * exported stuff + */ + +EXPORT_SYMBOL(rtc_register); +EXPORT_SYMBOL(rtc_unregister); +EXPORT_SYMBOL(rtc_control); + +int rtc_register(rtc_task_t *task) +{ +#if !RTC_IRQ + return -EIO; +#else + if (task == NULL || task->func == NULL) + return -EINVAL; + spin_lock_irq(&rtc_lock); + if (rtc_status & RTC_IS_OPEN) { + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + spin_lock(&rtc_task_lock); + if (rtc_callback) { + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + rtc_status |= RTC_IS_OPEN; + rtc_callback = task; + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return 0; +#endif +} + +int rtc_unregister(rtc_task_t *task) +{ +#if !RTC_IRQ + return -EIO; +#else + unsigned char tmp; + + spin_lock_irq(&rtc_task_lock); + if (rtc_callback != task) { + spin_unlock_irq(&rtc_task_lock); + return -ENXIO; + } + rtc_callback = NULL; + spin_lock(&rtc_lock); + /* disable controls */ + tmp = CMOS_READ(RTC_CONTROL); + tmp &= ~RTC_PIE; + tmp &= ~RTC_AIE; + tmp &= ~RTC_UIE; + CMOS_WRITE(tmp, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + if (rtc_status & RTC_TIMER_ON) { + rtc_status &= ~RTC_TIMER_ON; + del_timer(&rtc_irq_timer); + } + rtc_status &= ~RTC_IS_OPEN; + spin_unlock(&rtc_lock); + spin_unlock_irq(&rtc_task_lock); + return 0; +#endif +} + +int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) +{ +#if !RTC_IRQ + return -EIO; +#else + spin_lock_irq(&rtc_task_lock); + if (rtc_callback != task) { + spin_unlock_irq(&rtc_task_lock); + return -ENXIO; + } + spin_unlock_irq(&rtc_task_lock); + return rtc_do_ioctl(cmd, arg, 1); +#endif +} + + +/* * The various file operations we support. */ @@ -858,7 +952,6 @@ module_init(rtc_init); module_exit(rtc_exit); -EXPORT_NO_SYMBOLS; #if RTC_IRQ /* diff -ur linux/include/linux/rtc.h linux-2.4.23/include/linux/rtc.h --- linux/include/linux/rtc.h Thu Jan 15 14:40:40 2004 +++ linux-2.4.23/include/linux/rtc.h Fri Jan 16 23:22:19 2004 @@ -90,4 +90,18 @@ #define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ #define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ + +/* Exported functions to other kernel drivers */ + +#ifdef __KERNEL__ +typedef struct rtc_task { + void (*func)(void *private_data); + void *private_data; +} rtc_task_t; + +int rtc_register(rtc_task_t *task); +int rtc_unregister(rtc_task_t *task); +int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg); +#endif + #endif /* _LINUX_RTC_H_ */