diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Kconfig | 28 | ||||
-rw-r--r-- | drivers/char/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/bfin-otp.c | 189 | ||||
-rw-r--r-- | drivers/char/keyboard.c | 6 | ||||
-rw-r--r-- | drivers/char/mem.c | 133 | ||||
-rw-r--r-- | drivers/char/mwave/tp3780i.c | 14 |
6 files changed, 328 insertions, 43 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index a87b89d..2906ee7 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -481,6 +481,34 @@ config BRIQ_PANEL It's safe to say N here. +config BFIN_OTP + tristate "Blackfin On-Chip OTP Memory Support" + depends on BLACKFIN && (BF52x || BF54x) + default y + help + If you say Y here, you will get support for a character device + interface into the One Time Programmable memory pages that are + stored on the Blackfin processor. This will not get you access + to the secure memory pages however. You will need to write your + own secure code and reader for that. + + To compile this driver as a module, choose M here: the module + will be called bfin-otp. + + If unsure, it is safe to say Y. + +config BFIN_OTP_WRITE_ENABLE + bool "Enable writing support of OTP pages" + depends on BFIN_OTP + default n + help + If you say Y here, you will enable support for writing of the + OTP pages. This is dangerous by nature as you can only program + the pages once, so only enable this option when you actually + need it so as to not inadvertently clobber data. + + If unsure, say N. + config PRINTER tristate "Parallel printer support" depends on PARPORT diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 5407b76..4c1c584 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_VIOTAPE) += viotape.o obj-$(CONFIG_HVCS) += hvcs.o obj-$(CONFIG_SGI_MBCS) += mbcs.o obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o +obj-$(CONFIG_BFIN_OTP) += bfin-otp.o obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_TIPAR) += tipar.o diff --git a/drivers/char/bfin-otp.c b/drivers/char/bfin-otp.c new file mode 100644 index 0000000..0a01329 --- /dev/null +++ b/drivers/char/bfin-otp.c @@ -0,0 +1,189 @@ +/* + * Blackfin On-Chip OTP Memory Interface + * Supports BF52x/BF54x + * + * Copyright 2007-2008 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/types.h> + +#include <asm/blackfin.h> +#include <asm/uaccess.h> + +#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args) +#define stampit() stamp("here i am") +#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); }) + +#define DRIVER_NAME "bfin-otp" +#define PFX DRIVER_NAME ": " + +static DEFINE_MUTEX(bfin_otp_lock); + +/* OTP Boot ROM functions */ +#define _BOOTROM_OTP_COMMAND 0xEF000018 +#define _BOOTROM_OTP_READ 0xEF00001A +#define _BOOTROM_OTP_WRITE 0xEF00001C + +static u32 (* const otp_command)(u32 command, u32 value) = (void *)_BOOTROM_OTP_COMMAND; +static u32 (* const otp_read)(u32 page, u32 flags, u64 *page_content) = (void *)_BOOTROM_OTP_READ; +static u32 (* const otp_write)(u32 page, u32 flags, u64 *page_content) = (void *)_BOOTROM_OTP_WRITE; + +/* otp_command(): defines for "command" */ +#define OTP_INIT 0x00000001 +#define OTP_CLOSE 0x00000002 + +/* otp_{read,write}(): defines for "flags" */ +#define OTP_LOWER_HALF 0x00000000 /* select upper/lower 64-bit half (bit 0) */ +#define OTP_UPPER_HALF 0x00000001 +#define OTP_NO_ECC 0x00000010 /* do not use ECC */ +#define OTP_LOCK 0x00000020 /* sets page protection bit for page */ +#define OTP_ACCESS_READ 0x00001000 +#define OTP_ACCESS_READWRITE 0x00002000 + +/* Return values for all functions */ +#define OTP_SUCCESS 0x00000000 +#define OTP_MASTER_ERROR 0x001 +#define OTP_WRITE_ERROR 0x003 +#define OTP_READ_ERROR 0x005 +#define OTP_ACC_VIO_ERROR 0x009 +#define OTP_DATA_MULT_ERROR 0x011 +#define OTP_ECC_MULT_ERROR 0x021 +#define OTP_PREV_WR_ERROR 0x041 +#define OTP_DATA_SB_WARN 0x100 +#define OTP_ECC_SB_WARN 0x200 + +/** + * bfin_otp_read - Read OTP pages + * + * All reads must be in half page chunks (half page == 64 bits). + */ +static ssize_t bfin_otp_read(struct file *file, char __user *buff, size_t count, loff_t *pos) +{ + ssize_t bytes_done; + u32 page, flags, ret; + u64 content; + + stampit(); + + if (count % sizeof(u64)) + return -EMSGSIZE; + + if (mutex_lock_interruptible(&bfin_otp_lock)) + return -ERESTARTSYS; + + bytes_done = 0; + page = *pos / (sizeof(u64) * 2); + while (bytes_done < count) { + flags = (*pos % (sizeof(u64) * 2) ? OTP_UPPER_HALF : OTP_LOWER_HALF); + stamp("processing page %i (%s)", page, (flags == OTP_UPPER_HALF ? "upper" : "lower")); + ret = otp_read(page, flags, &content); + if (ret & OTP_MASTER_ERROR) { + bytes_done = -EIO; + break; + } + if (copy_to_user(buff + bytes_done, &content, sizeof(content))) { + bytes_done = -EFAULT; + break; + } + if (flags == OTP_UPPER_HALF) + ++page; + bytes_done += sizeof(content); + *pos += sizeof(content); + } + + mutex_unlock(&bfin_otp_lock); + + return bytes_done; +} + +#ifdef CONFIG_BFIN_OTP_WRITE_ENABLE +/** + * bfin_otp_write - Write OTP pages + * + * All writes must be in half page chunks (half page == 64 bits). + */ +static ssize_t bfin_otp_write(struct file *filp, const char __user *buff, size_t count, loff_t *pos) +{ + stampit(); + + if (count % sizeof(u64)) + return -EMSGSIZE; + + if (mutex_lock_interruptible(&bfin_otp_lock)) + return -ERESTARTSYS; + + /* need otp_init() documentation before this can be implemented */ + + mutex_unlock(&bfin_otp_lock); + + return -EINVAL; +} +#else +# define bfin_otp_write NULL +#endif + +static struct file_operations bfin_otp_fops = { + .owner = THIS_MODULE, + .read = bfin_otp_read, + .write = bfin_otp_write, +}; + +static struct miscdevice bfin_otp_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = DRIVER_NAME, + .fops = &bfin_otp_fops, +}; + +/** + * bfin_otp_init - Initialize module + * + * Registers the device and notifier handler. Actual device + * initialization is handled by bfin_otp_open(). + */ +static int __init bfin_otp_init(void) +{ + int ret; + + stampit(); + + ret = misc_register(&bfin_otp_misc_device); + if (ret) { + pr_init(KERN_ERR PFX "unable to register a misc device\n"); + return ret; + } + + pr_init(KERN_INFO PFX "initialized\n"); + + return 0; +} + +/** + * bfin_otp_exit - Deinitialize module + * + * Unregisters the device and notifier handler. Actual device + * deinitialization is handled by bfin_otp_close(). + */ +static void __exit bfin_otp_exit(void) +{ + stampit(); + + misc_deregister(&bfin_otp_misc_device); +} + +module_init(bfin_otp_init); +module_exit(bfin_otp_exit); + +MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>"); +MODULE_DESCRIPTION("Blackfin OTP Memory Interface"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 9769bf8..60b934a 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -42,6 +42,7 @@ #include <linux/input.h> #include <linux/reboot.h> #include <linux/notifier.h> +#include <linux/jiffies.h> extern void ctrl_alt_del(void); @@ -928,7 +929,8 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) if (up_flag) { if (brl_timeout) { if (!committing || - jiffies - releasestart > (brl_timeout * HZ) / 1000) { + time_after(jiffies, + releasestart + msecs_to_jiffies(brl_timeout))) { committing = pressed; releasestart = jiffies; } @@ -1238,6 +1240,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) } param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate; + param.ledstate = kbd->ledflagstate; key_map = key_maps[shift_final]; if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYCODE, ¶m) == NOTIFY_STOP || !key_map) { @@ -1286,6 +1289,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) (*k_handler[type])(vc, keysym & 0xff, !down); + param.ledstate = kbd->ledflagstate; atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, ¶m); if (type != KT_SLOCK) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 20070b7..e83623e 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -41,36 +41,7 @@ */ static inline int uncached_access(struct file *file, unsigned long addr) { -#if defined(__i386__) && !defined(__arch_um__) - /* - * On the PPro and successors, the MTRRs are used to set - * memory types for physical addresses outside main memory, - * so blindly setting PCD or PWT on those pages is wrong. - * For Pentiums and earlier, the surround logic should disable - * caching for the high addresses through the KEN pin, but - * we maintain the tradition of paranoia in this code. - */ - if (file->f_flags & O_SYNC) - return 1; - return !( test_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability) || - test_bit(X86_FEATURE_K6_MTRR, boot_cpu_data.x86_capability) || - test_bit(X86_FEATURE_CYRIX_ARR, boot_cpu_data.x86_capability) || - test_bit(X86_FEATURE_CENTAUR_MCR, boot_cpu_data.x86_capability) ) - && addr >= __pa(high_memory); -#elif defined(__x86_64__) && !defined(__arch_um__) - /* - * This is broken because it can generate memory type aliases, - * which can cause cache corruptions - * But it is only available for root and we have to be bug-to-bug - * compatible with i386. - */ - if (file->f_flags & O_SYNC) - return 1; - /* same behaviour as i386. PAT always set to cached and MTRRs control the - caching behaviour. - Hopefully a full PAT implementation will fix that soon. */ - return 0; -#elif defined(CONFIG_IA64) +#if defined(CONFIG_IA64) /* * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases. */ @@ -108,6 +79,36 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) } #endif +#ifdef CONFIG_NONPROMISC_DEVMEM +static inline int range_is_allowed(unsigned long pfn, unsigned long size) +{ + u64 from = ((u64)pfn) << PAGE_SHIFT; + u64 to = from + size; + u64 cursor = from; + + while (cursor < to) { + if (!devmem_is_allowed(pfn)) { + printk(KERN_INFO + "Program %s tried to access /dev/mem between %Lx->%Lx.\n", + current->comm, from, to); + return 0; + } + cursor += PAGE_SIZE; + pfn++; + } + return 1; +} +#else +static inline int range_is_allowed(unsigned long pfn, unsigned long size) +{ + return 1; +} +#endif + +void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr) +{ +} + /* * This funcion reads the *physical* memory. The f_pos points directly to the * memory location. @@ -150,15 +151,25 @@ static ssize_t read_mem(struct file * file, char __user * buf, sz = min_t(unsigned long, sz, count); + if (!range_is_allowed(p >> PAGE_SHIFT, count)) + return -EPERM; + /* * On ia64 if a page has been mapped somewhere as * uncached, then it must also be accessed uncached * by the kernel or data corruption may occur */ ptr = xlate_dev_mem_ptr(p); + if (!ptr) + return -EFAULT; - if (copy_to_user(buf, ptr, sz)) + if (copy_to_user(buf, ptr, sz)) { + unxlate_dev_mem_ptr(p, ptr); return -EFAULT; + } + + unxlate_dev_mem_ptr(p, ptr); + buf += sz; p += sz; count -= sz; @@ -207,20 +218,32 @@ static ssize_t write_mem(struct file * file, const char __user * buf, sz = min_t(unsigned long, sz, count); + if (!range_is_allowed(p >> PAGE_SHIFT, sz)) + return -EPERM; + /* * On ia64 if a page has been mapped somewhere as * uncached, then it must also be accessed uncached * by the kernel or data corruption may occur */ ptr = xlate_dev_mem_ptr(p); + if (!ptr) { + if (written) + break; + return -EFAULT; + } copied = copy_from_user(ptr, buf, sz); if (copied) { written += sz - copied; + unxlate_dev_mem_ptr(p, ptr); if (written) break; return -EFAULT; } + + unxlate_dev_mem_ptr(p, ptr); + buf += sz; p += sz; count -= sz; @@ -231,6 +254,12 @@ static ssize_t write_mem(struct file * file, const char __user * buf, return written; } +int __attribute__((weak)) phys_mem_access_prot_allowed(struct file *file, + unsigned long pfn, unsigned long size, pgprot_t *vma_prot) +{ + return 1; +} + #ifndef __HAVE_PHYS_MEM_ACCESS_PROT static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot) @@ -271,6 +300,35 @@ static inline int private_mapping_ok(struct vm_area_struct *vma) } #endif +void __attribute__((weak)) +map_devmem(unsigned long pfn, unsigned long len, pgprot_t prot) +{ + /* nothing. architectures can override. */ +} + +void __attribute__((weak)) +unmap_devmem(unsigned long pfn, unsigned long len, pgprot_t prot) +{ + /* nothing. architectures can override. */ +} + +static void mmap_mem_open(struct vm_area_struct *vma) +{ + map_devmem(vma->vm_pgoff, vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + +static void mmap_mem_close(struct vm_area_struct *vma) +{ + unmap_devmem(vma->vm_pgoff, vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + +static struct vm_operations_struct mmap_mem_ops = { + .open = mmap_mem_open, + .close = mmap_mem_close +}; + static int mmap_mem(struct file * file, struct vm_area_struct * vma) { size_t size = vma->vm_end - vma->vm_start; @@ -281,17 +339,28 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) if (!private_mapping_ok(vma)) return -ENOSYS; + if (!range_is_allowed(vma->vm_pgoff, size)) + return -EPERM; + + if (!phys_mem_access_prot_allowed(file, vma->vm_pgoff, size, + &vma->vm_page_prot)) + return -EINVAL; + vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, size, vma->vm_page_prot); + vma->vm_ops = &mmap_mem_ops; + /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size, - vma->vm_page_prot)) + vma->vm_page_prot)) { + unmap_devmem(vma->vm_pgoff, size, vma->vm_page_prot); return -EAGAIN; + } return 0; } diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c index 37fe80d..f282976 100644 --- a/drivers/char/mwave/tp3780i.c +++ b/drivers/char/mwave/tp3780i.c @@ -97,24 +97,20 @@ static void EnableSRAM(THINKPAD_BD_DATA * pBDData) static irqreturn_t UartInterrupt(int irq, void *dev_id) { - int irqno = (int)(unsigned long) dev_id; - PRINTK_3(TRACE_TP3780I, - "tp3780i::UartInterrupt entry irq %x dev_id %p\n", irqno, dev_id); + "tp3780i::UartInterrupt entry irq %x dev_id %p\n", irq, dev_id); return IRQ_HANDLED; } static irqreturn_t DspInterrupt(int irq, void *dev_id) { - int irqno = (int)(unsigned long) dev_id; - pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd; DSP_3780I_CONFIG_SETTINGS *pSettings = &pDrvData->rBDData.rDspSettings; unsigned short usDspBaseIO = pSettings->usDspBaseIO; unsigned short usIPCSource = 0, usIsolationMask, usPCNum; PRINTK_3(TRACE_TP3780I, - "tp3780i::DspInterrupt entry irq %x dev_id %p\n", irqno, dev_id); + "tp3780i::DspInterrupt entry irq %x dev_id %p\n", irq, dev_id); if (dsp3780I_GetIPCSource(usDspBaseIO, &usIPCSource) == 0) { PRINTK_2(TRACE_TP3780I, @@ -365,16 +361,14 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) pSettings->bPllBypass = TP_CFG_PllBypass; pSettings->usChipletEnable = TP_CFG_ChipletEnable; - if (request_irq(pSettings->usUartIrq, &UartInterrupt, 0, "mwave_uart", - (void *)(unsigned long) pSettings->usUartIrq)) { + if (request_irq(pSettings->usUartIrq, &UartInterrupt, 0, "mwave_uart", NULL)) { PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Could not get UART IRQ %x\n", pSettings->usUartIrq); goto exit_cleanup; } else { /* no conflict just release */ free_irq(pSettings->usUartIrq, NULL); } - if (request_irq(pSettings->usDspIrq, &DspInterrupt, 0, "mwave_3780i", - (void *)(unsigned long) pSettings->usDspIrq)) { + if (request_irq(pSettings->usDspIrq, &DspInterrupt, 0, "mwave_3780i", NULL)) { PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: Could not get 3780i IRQ %x\n", pSettings->usDspIrq); goto exit_cleanup; } else { |