default:
fprintf(stderr, "Unknown nla_type %d\n",
na->nla_type);
+ case TASKSTATS_TYPE_NULL:
break;
}
na = (struct nlattr *) (GENLMSG_DATA(&msg) + len);
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
locking rules:
- none have BKL
dcache_lock rename_lock ->d_lock may block
d_revalidate: no no no yes
d_hash no no no yes
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
int (*readlink) (struct dentry *, char __user *,int);
- int (*follow_link) (struct dentry *, struct nameidata *);
+ void * (*follow_link) (struct dentry *, struct nameidata *);
+ void (*put_link) (struct dentry *, struct nameidata *, void *);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, struct nameidata *);
+ int (*check_acl)(struct inode *, int);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *);
+ void (*truncate_range)(struct inode *, loff_t, loff_t);
+ long (*fallocate)(struct inode *inode, int mode, loff_t offset, loff_t len);
+ int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
locking rules:
- all may block, none have BKL
+ all may block
i_mutex(inode)
lookup: yes
create: yes
rename: yes (all) (see below)
readlink: no
follow_link: no
+put_link: no
truncate: yes (see below)
setattr: yes
permission: no
+check_acl: no
getattr: no
setxattr: yes
getxattr: no
listxattr: no
removexattr: yes
+truncate_range: yes
+fallocate: no
+fiemap: no
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
victim.
cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
->truncate() is never called directly - it's a callback, not a
-method. It's called by vmtruncate() - library function normally used by
+method. It's called by vmtruncate() - deprecated library function used by
->setattr(). Locking information above applies to that call (i.e. is
inherited from ->setattr() - vmtruncate() is used when ATTR_SIZE had been
passed).
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);
void (*dirty_inode) (struct inode *);
- int (*write_inode) (struct inode *, int);
+ int (*write_inode) (struct inode *, struct writeback_control *wbc);
int (*drop_inode) (struct inode *);
void (*evict_inode) (struct inode *);
void (*put_super) (struct super_block *);
int (*show_options)(struct seq_file *, struct vfsmount *);
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
+ int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
locking rules:
All may block [not true, see below]
- None have BKL
s_umount
alloc_inode:
destroy_inode:
show_options: no (namespace_sem)
quota_read: no (see below)
quota_write: no (see below)
+bdev_try_to_free_page: no (see below)
->statfs() has s_umount (shared) when called by ustat(2) (native or
compat), but that's an accident of bad API; s_umount is used to pin
dqio_sem) (unless an admin really wants to screw up something and
writes to quota files with quotas on). For other details about locking
see also dquot_operations section.
+->bdev_try_to_free_page is called from the ->releasepage handler of
+the block device inode. See there for more details.
--------------------------- file_system_type ---------------------------
prototypes:
int (*get_sb) (struct file_system_type *, int,
const char *, void *, struct vfsmount *);
+ struct dentry *(*mount) (struct file_system_type *, int,
+ const char *, void *);
void (*kill_sb) (struct super_block *);
locking rules:
- may block BKL
-get_sb yes no
-kill_sb yes no
+ may block
+get_sb yes
+mount yes
+kill_sb yes
->get_sb() returns error or 0 with locked superblock attached to the vfsmount
(exclusive on ->s_umount).
+->mount() returns ERR_PTR or the root dentry.
->kill_sb() takes a write-locked superblock, does all shutdown work on it,
unlocks and drops the reference.
void (*freepage)(struct page *);
int (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
loff_t offset, unsigned long nr_segs);
- int (*launder_page) (struct page *);
+ int (*get_xip_mem)(struct address_space *, pgoff_t, int, void **,
+ unsigned long *);
+ int (*migratepage)(struct address_space *, struct page *, struct page *);
+ int (*launder_page)(struct page *);
+ int (*is_partially_uptodate)(struct page *, read_descriptor_t *, unsigned long);
+ int (*error_remove_page)(struct address_space *, struct page *);
locking rules:
All except set_page_dirty and freepage may block
- BKL PageLocked(page) i_mutex
-writepage: no yes, unlocks (see below)
-readpage: no yes, unlocks
-sync_page: no maybe
-writepages: no
-set_page_dirty no no
-readpages: no
-write_begin: no locks the page yes
-write_end: no yes, unlocks yes
-perform_write: no n/a yes
-bmap: no
-invalidatepage: no yes
-releasepage: no yes
-freepage: no yes
-direct_IO: no
-launder_page: no yes
+ PageLocked(page) i_mutex
+writepage: yes, unlocks (see below)
+readpage: yes, unlocks
+sync_page: maybe
+writepages:
+set_page_dirty no
+readpages:
+write_begin: locks the page yes
+write_end: yes, unlocks yes
+bmap:
+invalidatepage: yes
+releasepage: yes
+freepage: yes
+direct_IO:
+get_xip_mem: maybe
+migratepage: yes (both)
+launder_page: yes
+is_partially_uptodate: yes
+error_remove_page: yes
->write_begin(), ->write_end(), ->sync_page() and ->readpage()
may be called from the request handler (/dev/loop).
not locked.
->bmap() is currently used by legacy ioctl() (FIBMAP) provided by some
-filesystems and by the swapper. The latter will eventually go away. All
-instances do not actually need the BKL. Please, keep it that way and don't
-breed new callers.
+filesystems and by the swapper. The latter will eventually go away. Please,
+keep it that way and don't breed new callers.
->invalidatepage() is called when the filesystem must attempt to drop
some or all of the buffers from the page when it is being truncated. It
getting mapped back in and redirtied, it needs to be kept locked
across the entire operation.
- Note: currently almost all instances of address_space methods are
-using BKL for internal serialization and that's one of the worst sources
-of contention. Normally they are calling library functions (in fs/buffer.c)
-and pass foo_get_block() as a callback (on local block-based filesystems,
-indeed). BKL is not needed for library stuff and is usually taken by
-foo_get_block(). It's an overkill, since block bitmaps can be protected by
-internal fs locking and real critical areas are much smaller than the areas
-filesystems protect now.
-
----------------------- file_lock_operations ------------------------------
prototypes:
- void (*fl_insert)(struct file_lock *); /* lock insertion callback */
- void (*fl_remove)(struct file_lock *); /* lock removal callback */
void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
void (*fl_release_private)(struct file_lock *);
locking rules:
- BKL may block
-fl_insert: yes no
-fl_remove: yes no
-fl_copy_lock: yes no
-fl_release_private: yes yes
+ file_lock_lock may block
+fl_copy_lock: yes no
+fl_release_private: maybe no
----------------------- lock_manager_operations ---------------------------
prototypes:
int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
void (*fl_notify)(struct file_lock *); /* unblock callback */
+ int (*fl_grant)(struct file_lock *, struct file_lock *, int);
void (*fl_release_private)(struct file_lock *);
void (*fl_break)(struct file_lock *); /* break_lease callback */
+ int (*fl_mylease)(struct file_lock *, struct file_lock *);
+ int (*fl_change)(struct file_lock **, int);
locking rules:
- BKL may block
-fl_compare_owner: yes no
-fl_notify: yes no
-fl_release_private: yes yes
-fl_break: yes no
-
- Currently only NFSD and NLM provide instances of this class. None of the
-them block. If you have out-of-tree instances - please, show up. Locking
-in that area will change.
+ file_lock_lock may block
+fl_compare_owner: yes no
+fl_notify: yes no
+fl_grant: no no
+fl_release_private: maybe no
+fl_break: yes no
+fl_mylease: yes no
+fl_change yes no
+
--------------------------- buffer_head -----------------------------------
prototypes:
void (*b_end_io)(struct buffer_head *bh, int uptodate);
void (*swap_slot_free_notify) (struct block_device *, unsigned long);
locking rules:
- BKL bd_mutex
-open: no yes
-release: no yes
-ioctl: no no
-compat_ioctl: no no
-direct_access: no no
-media_changed: no no
-unlock_native_capacity: no no
-revalidate_disk: no no
-getgeo: no no
-swap_slot_free_notify: no no (see below)
+ bd_mutex
+open: yes
+release: yes
+ioctl: no
+compat_ioctl: no
+direct_access: no
+media_changed: no
+unlock_native_capacity: no
+revalidate_disk: no
+getgeo: no
+swap_slot_free_notify: no (see below)
media_changed, unlock_native_capacity and revalidate_disk are called only from
check_disk_change().
unsigned long (*get_unmapped_area)(struct file *, unsigned long,
unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
+ int (*flock) (struct file *, int, struct file_lock *);
+ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *,
+ size_t, unsigned int);
+ ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,
+ size_t, unsigned int);
+ int (*setlease)(struct file *, long, struct file_lock **);
};
locking rules:
- All may block.
- BKL
-llseek: no (see below)
-read: no
-aio_read: no
-write: no
-aio_write: no
-readdir: no
-poll: no
-unlocked_ioctl: no
-compat_ioctl: no
-mmap: no
-open: no
-flush: no
-release: no
-fsync: no (see below)
-aio_fsync: no
-fasync: no
-lock: yes
-readv: no
-writev: no
-sendfile: no
-sendpage: no
-get_unmapped_area: no
-check_flags: no
+ All may block except for ->setlease.
+ No VFS locks held on entry except for ->fsync and ->setlease.
+
+->fsync() has i_mutex on inode.
+
+->setlease has the file_list_lock held and must not sleep.
->llseek() locking has moved from llseek to the individual llseek
implementations. If your fs is not using generic_file_llseek, you
Note: this does not protect the file->f_pos against concurrent modifications
since this is something the userspace has to take care about.
-Note: ext2_release() was *the* source of contention on fs-intensive
-loads and dropping BKL on ->release() helps to get rid of that (we still
-grab BKL for cases when we close a file that had been opened r/w, but that
-can and should be done using the internal locking with smaller critical areas).
-Current worst offender is ext2_get_block()...
-
-->fasync() is called without BKL protection, and is responsible for
-maintaining the FASYNC bit in filp->f_flags. Most instances call
-fasync_helper(), which does that maintenance, so it's not normally
-something one needs to worry about. Return values > 0 will be mapped to
-zero in the VFS layer.
+->fasync() is responsible for maintaining the FASYNC bit in filp->f_flags.
+Most instances call fasync_helper(), which does that maintenance, so it's
+not normally something one needs to worry about. Return values > 0 will be
+mapped to zero in the VFS layer.
->readdir() and ->ioctl() on directories must be changed. Ideally we would
move ->readdir() to inode_operations and use a separate method for directory
->read on directories probably must go away - we should just enforce -EISDIR
in sys_read() and friends.
-->fsync() has i_mutex on inode.
-
--------------------------- dquot_operations -------------------------------
prototypes:
int (*write_dquot) (struct dquot *);
int (*access)(struct vm_area_struct *, unsigned long, void*, int, int);
locking rules:
- BKL mmap_sem PageLocked(page)
-open: no yes
-close: no yes
-fault: no yes can return with page locked
-page_mkwrite: no yes can return with page locked
-access: no yes
+ mmap_sem PageLocked(page)
+open: yes
+close: yes
+fault: yes can return with page locked
+page_mkwrite: yes can return with page locked
+access: yes
->fault() is called when a previously not present pte is about
to be faulted in. The filesystem must find and return the page associated
(if you break something or notice that it is broken and do not fix it yourself
- at least put it here)
-
-ipc/shm.c::shm_delete() - may need BKL.
-->read() and ->write() in many drivers are (probably) missing BKL.
nousb [USB] Disable the USB subsystem
- nowatchdog [KNL] Disable the lockup detector.
+ nowatchdog [KNL] Disable the lockup detector (NMI watchdog).
nowb [ARM]
reset_devices [KNL] Force drivers to reset the underlying device
during initialization.
- resource_alloc_from_bottom
- Allocate new resources from the beginning of available
- space, not the end. If you need to use this, please
- report a bug.
-
resume= [SWSUSP]
Specify the partition device for software suspend
zero)
bool pm_runtime_suspended(struct device *dev);
- - return true if the device's runtime PM status is 'suspended', or false
- otherwise
+ - return true if the device's runtime PM status is 'suspended' and its
+ 'power.disable_depth' field is equal to zero, or false otherwise
void pm_runtime_allow(struct device *dev);
- set the power.runtime_auto flag for the device and decrease its usage
/**
- * queuecommand - queue scsi command, invoke 'done' on completion
+ * queuecommand - queue scsi command, invoke scp->scsi_done on completion
+ * @shost: pointer to the scsi host object
* @scp: pointer to scsi command object
- * @done: function pointer to be invoked on completion
*
* Returns 0 on success.
*
*
* Other types of errors that are detected immediately may be
* flagged by setting scp->result to an appropriate value,
- * invoking the 'done' callback, and then returning 0 from this
- * function. If the command is not performed immediately (and the
- * LLD is starting (or will start) the given command) then this
- * function should place 0 in scp->result and return 0.
+ * invoking the scp->scsi_done callback, and then returning 0
+ * from this function. If the command is not performed
+ * immediately (and the LLD is starting (or will start) the given
+ * command) then this function should place 0 in scp->result and
+ * return 0.
*
* Command ownership. If the driver returns zero, it owns the
- * command and must take responsibility for ensuring the 'done'
- * callback is executed. Note: the driver may call done before
- * returning zero, but after it has called done, it may not
- * return any value other than zero. If the driver makes a
- * non-zero return, it must not execute the command's done
- * callback at any time.
- *
- * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave")
- * and is expected to be held on return.
+ * command and must take responsibility for ensuring the
+ * scp->scsi_done callback is executed. Note: the driver may
+ * call scp->scsi_done before returning zero, but after it has
+ * called scp->scsi_done, it may not return any value other than
+ * zero. If the driver makes a non-zero return, it must not
+ * execute the command's scsi_done callback at any time.
+ *
+ * Locks: up to and including 2.6.36, struct Scsi_Host::host_lock
+ * held on entry (with "irqsave") and is expected to be
+ * held on return. From 2.6.37 onwards, queuecommand is
+ * called without any locks held.
*
* Calling context: in interrupt (soft irq) or process context
*
- * Notes: This function should be relatively fast. Normally it will
- * not wait for IO to complete. Hence the 'done' callback is invoked
- * (often directly from an interrupt service routine) some time after
- * this function has returned. In some cases (e.g. pseudo adapter
- * drivers that manufacture the response to a SCSI INQUIRY)
- * the 'done' callback may be invoked before this function returns.
- * If the 'done' callback is not invoked within a certain period
- * the SCSI mid level will commence error processing.
- * If a status of CHECK CONDITION is placed in "result" when the
- * 'done' callback is invoked, then the LLD driver should
- * perform autosense and fill in the struct scsi_cmnd::sense_buffer
+ * Notes: This function should be relatively fast. Normally it
+ * will not wait for IO to complete. Hence the scp->scsi_done
+ * callback is invoked (often directly from an interrupt service
+ * routine) some time after this function has returned. In some
+ * cases (e.g. pseudo adapter drivers that manufacture the
+ * response to a SCSI INQUIRY) the scp->scsi_done callback may be
+ * invoked before this function returns. If the scp->scsi_done
+ * callback is not invoked within a certain period the SCSI mid
+ * level will commence error processing. If a status of CHECK
+ * CONDITION is placed in "result" when the scp->scsi_done
+ * callback is invoked, then the LLD driver should perform
+ * autosense and fill in the struct scsi_cmnd::sense_buffer
* array. The scsi_cmnd::sense_buffer array is zeroed prior to
* the mid level queuing a command to an LLD.
*
* Defined in: LLD
**/
- int queuecommand(struct scsi_cmnd * scp,
- void (*done)(struct scsi_cmnd *))
+ int queuecommand(struct Scsi_Host *shost, struct scsi_cmnd * scp)
/**
print " $regex_lru_isolate/o\n";
next;
}
+ my $isolate_mode = $1;
my $nr_scanned = $4;
my $nr_contig_dirty = $7;
- $perprocesspid{$process_pid}->{HIGH_NR_SCANNED} += $nr_scanned;
+
+ # To closer match vmstat scanning statistics, only count isolate_both
+ # and isolate_inactive as scanning. isolate_active is rotation
+ # isolate_inactive == 0
+ # isolate_active == 1
+ # isolate_both == 2
+ if ($isolate_mode != 1) {
+ $perprocesspid{$process_pid}->{HIGH_NR_SCANNED} += $nr_scanned;
+ }
$perprocesspid{$process_pid}->{HIGH_NR_CONTIG_DIRTY} += $nr_contig_dirty;
} elsif ($tracepoint eq "mm_vmscan_lru_shrink_inactive") {
$details = $5;
F: drivers/usb/gadget/amd5536udc.*
AMD GEODE PROCESSOR/CHIPSET SUPPORT
-P: Jordan Crouse
+P: Andres Salomon <dilinger@queued.net>
L: linux-geode@lists.infradead.org (moderated for non-subscribers)
W: http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
S: Supported
ARM/NOMADIK ARCHITECTURE
M: Alessandro Rubini <rubini@unipv.it>
+M: Linus Walleij <linus.walleij@stericsson.com>
M: STEricsson <STEricsson_nomadik_linux@list.st.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-nomadik/
F: arch/arm/plat-nomadik/
+F: drivers/i2c/busses/i2c-nomadik.c
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
M: Nelson Castillo <arhuaco@freaks-unidos.net>
F: drivers/rtc/rtc-coh901331.c
F: drivers/watchdog/coh901327_wdt.c
F: drivers/dma/coh901318*
+F: drivers/mfd/ab3100*
+F: drivers/rtc/rtc-ab3100.c
+F: drivers/rtc/rtc-coh901331.c
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
-ARM/U8500 ARM ARCHITECTURE
+ARM/Ux500 ARM ARCHITECTURE
M: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+M: Linus Walleij <linus.walleij@stericsson.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-ux500/
+F: drivers/dma/ste_dma40*
+F: drivers/mfd/ab3550*
+F: drivers/mfd/abx500*
+F: drivers/mfd/ab8500*
+F: drivers/mfd/stmpe*
+F: drivers/rtc/rtc-ab8500.c
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
ARM/VFP SUPPORT
M: Russell King <linux@arm.linux.org.uk>
F: include/pcmcia/
PCNET32 NETWORK DRIVER
-M: Don Fry <pcnet32@verizon.net>
+M: Don Fry <pcnet32@frontier.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/pcnet32.c
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 37
-EXTRAVERSION = -rc6
+EXTRAVERSION =
NAME = Flesh-Eating Bats with Fangs
# *DOCUMENTATION*
return pci_scan_bus(nr, &it8152_ops, sys);
}
+EXPORT_SYMBOL(dma_set_coherent_mask);
IT8152_PD_IRQ(0) Audio controller (ACR)
*/
#define IT8152_IRQ(x) (IRQ_BOARD_START + (x))
+#define IT8152_LAST_IRQ (IRQ_BOARD_START + 40)
/* IRQ-sources in 3 groups - local devices, LPC (serial), and external PCI */
#define IT8152_LD_IRQ_COUNT 9
extern void *kmap_high_get(struct page *page);
extern void kunmap_high(struct page *page);
-extern void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte);
-extern void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte);
-
/*
* The following functions are already defined by <linux/highmem.h>
* when CONFIG_HIGHMEM is not set.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/* DO NOT EDIT!! - this file automatically generated
- * from .s file by awk -f s2h.awk
- */
/* Size definitions
* Copyright (C) ARM Limited 1998. All rights reserved.
*/
/* handy sizes */
#define SZ_16 0x00000010
+#define SZ_32 0x00000020
+#define SZ_64 0x00000040
+#define SZ_128 0x00000080
#define SZ_256 0x00000100
#define SZ_512 0x00000200
#define rmb() dmb()
#define wmb() mb()
#else
+#include <asm/memory.h>
#define mb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
#define rmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
#define wmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
ldr r1, [tsk, #TI_FLAGS]
tst r1, #_TIF_WORK_MASK
bne fast_work_pending
+#if defined(CONFIG_IRQSOFF_TRACER)
+ asm_trace_hardirqs_on
+#endif
/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr
tst r1, #_TIF_WORK_MASK
bne work_pending
no_work_pending:
+#if defined(CONFIG_IRQSOFF_TRACER)
+ asm_trace_hardirqs_on
+#endif
/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr
* All kernel threads share the same mm context; grab a
* reference and switch to it.
*/
- atomic_inc(&mm->mm_users);
atomic_inc(&mm->mm_count);
current->active_mm = mm;
cpumask_set_cpu(cpu, mm_cpumask(mm));
obj-$(CONFIG_MACH_CPU9G20) += board-cpu9krea.o
obj-$(CONFIG_MACH_STAMP9G20) += board-stamp9g20.o
obj-$(CONFIG_MACH_PORTUXG20) += board-stamp9g20.o
-obj-$(CONFIG_MACH_PCONTROL_G20) += board-pcontrol-g20.o
+obj-$(CONFIG_MACH_PCONTROL_G20) += board-pcontrol-g20.o board-stamp9g20.o
# AT91SAM9260/AT91SAM9G20 board-specific support
obj-$(CONFIG_MACH_SNAPPER_9260) += board-snapper9260.o
#include <mach/board.h>
#include <mach/at91sam9_smc.h>
+#include <mach/stamp9g20.h>
#include "sam9_smc.h"
#include "generic.h"
static void __init pcontrol_g20_map_io(void)
{
- /* Initialize processor: 18.432 MHz crystal */
- at91sam9260_initialize(18432000);
-
- /* DGBU on ttyS0. (Rx, Tx) only TTL -> JTAG connector X7 17,19 ) */
- at91_register_uart(0, 0, 0);
+ stamp9g20_map_io();
/* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback A2 */
at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
/* USART2 on ttyS3. (Rx, Tx) 9bit-Bus Multidrop-mode X4 */
at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
}
-/*
- * NAND flash 512MiB 1,8V 8-bit, sector size 128 KiB
- */
-static struct atmel_nand_data __initdata nand_data = {
- .ale = 21,
- .cle = 22,
- .rdy_pin = AT91_PIN_PC13,
- .enable_pin = AT91_PIN_PC14,
-};
-
-/*
- * Bus timings; unit = 7.57ns
- */
-static struct sam9_smc_config __initdata nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 2,
- .ncs_write_setup = 0,
- .nwe_setup = 2,
-
- .ncs_read_pulse = 4,
- .nrd_pulse = 4,
- .ncs_write_pulse = 4,
- .nwe_pulse = 4,
-
- .read_cycle = 7,
- .write_cycle = 7,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
- | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
- .tdf_cycles = 3,
-};
-
static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { {
.ncs_read_setup = 16,
.nrd_setup = 18,
.tdf_cycles = 1,
} };
-static void __init add_device_nand(void)
-{
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(3, &nand_smc_config);
- at91_add_device_nand(&nand_data);
-}
-
-
static void __init add_device_pcontrol(void)
{
/* configure chip-select 4 (IO compatible to 8051 X4 ) */
/*
- * MCI (SD/MMC)
- * det_pin, wp_pin and vcc_pin are not connected
- */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
-static struct mci_platform_data __initdata mmc_data = {
- .slot[0] = {
- .bus_width = 4,
- },
-};
-#else
-static struct at91_mmc_data __initdata mmc_data = {
- .wire4 = 1,
-};
-#endif
-
-
-/*
* USB Host port
*/
static struct at91_usbh_data __initdata usbh_data = {
};
-/*
- * Dallas 1-Wire DS2431
- */
-static struct w1_gpio_platform_data w1_gpio_pdata = {
- .pin = AT91_PIN_PA29,
- .is_open_drain = 1,
-};
-
-static struct platform_device w1_device = {
- .name = "w1-gpio",
- .id = -1,
- .dev.platform_data = &w1_gpio_pdata,
-};
-
-static void add_wire1(void)
-{
- at91_set_GPIO_periph(w1_gpio_pdata.pin, 1);
- at91_set_multi_drive(w1_gpio_pdata.pin, 1);
- platform_device_register(&w1_device);
-}
-
-
static void __init pcontrol_g20_board_init(void)
{
- at91_add_device_serial();
- add_device_nand();
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
- at91_add_device_mci(0, &mmc_data);
-#else
- at91_add_device_mmc(0, &mmc_data);
-#endif
+ stamp9g20_board_init();
at91_add_device_usbh(&usbh_data);
at91_add_device_eth(&macb_data);
at91_add_device_i2c(pcontrol_g20_i2c_devices,
ARRAY_SIZE(pcontrol_g20_i2c_devices));
- add_wire1();
add_device_pcontrol();
at91_add_device_spi(pcontrol_g20_spi_devices,
ARRAY_SIZE(pcontrol_g20_spi_devices));
#include "generic.h"
-static void __init portuxg20_map_io(void)
+void __init stamp9g20_map_io(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91sam9260_initialize(18432000);
/* DGBU on ttyS0. (Rx & Tx only) */
at91_register_uart(0, 0, 0);
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
+}
+
+static void __init stamp9g20evb_map_io(void)
+{
+ stamp9g20_map_io();
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR
+ | ATMEL_UART_DCD | ATMEL_UART_RI);
+}
+
+static void __init portuxg20_map_io(void)
+{
+ stamp9g20_map_io();
+
/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
| ATMEL_UART_DTR | ATMEL_UART_DSR
/* USART5 on ttyS6. (Rx, Tx only) */
at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
-}
-
-static void __init stamp9g20_map_io(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91sam9260_initialize(18432000);
-
- /* DGBU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR
- | ATMEL_UART_DCD | ATMEL_UART_RI);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static void __init init_irq(void)
.pullup_pin = 0, /* pull-up driven by UDC */
};
-static struct at91_udc_data __initdata stamp9g20_udc_data = {
+static struct at91_udc_data __initdata stamp9g20evb_udc_data = {
.vbus_pin = AT91_PIN_PA22,
.pullup_pin = 0, /* pull-up driven by UDC */
};
}
};
-static struct gpio_led stamp9g20_leds[] = {
+static struct gpio_led stamp9g20evb_leds[] = {
{
.name = "D8",
.gpio = AT91_PIN_PB18,
}
-static void __init generic_board_init(void)
+void __init stamp9g20_board_init(void)
{
/* Serial */
at91_add_device_serial();
#else
at91_add_device_mmc(0, &mmc_data);
#endif
- /* USB Host */
- at91_add_device_usbh(&usbh_data);
- /* Ethernet */
- at91_add_device_eth(&macb_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
/* W1 */
add_w1();
}
static void __init portuxg20_board_init(void)
{
- generic_board_init();
- /* SPI */
- at91_add_device_spi(portuxg20_spi_devices, ARRAY_SIZE(portuxg20_spi_devices));
+ stamp9g20_board_init();
+ /* USB Host */
+ at91_add_device_usbh(&usbh_data);
/* USB Device */
at91_add_device_udc(&portuxg20_udc_data);
+ /* Ethernet */
+ at91_add_device_eth(&macb_data);
+ /* I2C */
+ at91_add_device_i2c(NULL, 0);
+ /* SPI */
+ at91_add_device_spi(portuxg20_spi_devices, ARRAY_SIZE(portuxg20_spi_devices));
/* LEDs */
at91_gpio_leds(portuxg20_leds, ARRAY_SIZE(portuxg20_leds));
}
-static void __init stamp9g20_board_init(void)
+static void __init stamp9g20evb_board_init(void)
{
- generic_board_init();
+ stamp9g20_board_init();
+ /* USB Host */
+ at91_add_device_usbh(&usbh_data);
/* USB Device */
- at91_add_device_udc(&stamp9g20_udc_data);
+ at91_add_device_udc(&stamp9g20evb_udc_data);
+ /* Ethernet */
+ at91_add_device_eth(&macb_data);
+ /* I2C */
+ at91_add_device_i2c(NULL, 0);
/* LEDs */
- at91_gpio_leds(stamp9g20_leds, ARRAY_SIZE(stamp9g20_leds));
+ at91_gpio_leds(stamp9g20evb_leds, ARRAY_SIZE(stamp9g20evb_leds));
}
MACHINE_START(PORTUXG20, "taskit PortuxG20")
/* Maintainer: taskit GmbH */
.boot_params = AT91_SDRAM_BASE + 0x100,
.timer = &at91sam926x_timer,
- .map_io = stamp9g20_map_io,
+ .map_io = stamp9g20evb_map_io,
.init_irq = init_irq,
- .init_machine = stamp9g20_board_init,
+ .init_machine = stamp9g20evb_board_init,
MACHINE_END
/* Now set uhpck values */
uhpck.parent = &utmi_clk;
uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
- uhpck.rate_hz = utmi_clk.parent->rate_hz;
+ uhpck.rate_hz = utmi_clk.rate_hz;
uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8);
}
#define AT91_MCI_TRTYP_BLOCK (0 << 19)
#define AT91_MCI_TRTYP_MULTIPLE (1 << 19)
#define AT91_MCI_TRTYP_STREAM (2 << 19)
+#define AT91_MCI_TRTYP_SDIO_BYTE (4 << 19)
+#define AT91_MCI_TRTYP_SDIO_BLOCK (5 << 19)
#define AT91_MCI_BLKR 0x18 /* Block Register */
#define AT91_MCI_BLKR_BCNT(n) ((0xffff & (n)) << 0) /* Block count */
--- /dev/null
+#ifndef __MACH_STAMP9G20_H
+#define __MACH_STAMP9G20_H
+
+void stamp9g20_map_io(void);
+void stamp9g20_board_init(void);
+
+#endif
EXPORT_SYMBOL(ixp4xx_pci_read);
EXPORT_SYMBOL(ixp4xx_pci_write);
-
+EXPORT_SYMBOL(dma_set_coherent_mask);
config ARCH_PXA_ESERIES
bool "PXA based Toshiba e-series PDAs"
select PXA25x
+ select FB_W100
config MACH_E330
bool "Toshiba e330"
@ Let us ensure we jump to resume_after_mmu only when the mcr above
@ actually took effect. They call it the "cpwait" operation.
- mrc p15, 0, r1, c2, c0, 0 @ queue a dependency on CP15
- sub pc, r2, r1, lsr #32 @ jump to virtual addr
+ mrc p15, 0, r0, c2, c0, 0 @ queue a dependency on CP15
+ sub pc, r2, r0, lsr #32 @ jump to virtual addr
nop
nop
nop
config S3C2412_PM
bool
+ select S3C2412_PM_SLEEP
help
Internal config node to apply S3C2412 power management
+config S3C2412_PM_SLEEP
+ bool
+ help
+ Internal config node to apply sleep for S3C2412 power management.
+ Can be selected by another SoCs with similar sleep procedure.
+
# Note, the S3C2412 IOtiming support is in plat-s3c24xx
config S3C2412_CPUFREQ
obj-$(CONFIG_CPU_S3C2412) += clock.o
obj-$(CONFIG_CPU_S3C2412) += gpio.o
obj-$(CONFIG_S3C2412_DMA) += dma.o
-obj-$(CONFIG_S3C2412_PM) += pm.o sleep.o
+obj-$(CONFIG_S3C2412_PM) += pm.o
+obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep.o
obj-$(CONFIG_S3C2412_CPUFREQ) += cpu-freq.o
# Machine support
config S3C2416_PM
bool
+ select S3C2412_PM_SLEEP
help
Internal config node to apply S3C2416 power management
static struct max8998_platform_data aquila_max8998_pdata = {
.num_regulators = ARRAY_SIZE(aquila_regulators),
.regulators = aquila_regulators,
+ .buck1_set1 = S5PV210_GPH0(3),
+ .buck1_set2 = S5PV210_GPH0(4),
+ .buck2_set3 = S5PV210_GPH0(5),
+ .buck1_max_voltage1 = 1200000,
+ .buck1_max_voltage2 = 1200000,
+ .buck2_max_voltage = 1200000,
};
#endif
static struct max8998_platform_data goni_max8998_pdata = {
.num_regulators = ARRAY_SIZE(goni_regulators),
.regulators = goni_regulators,
+ .buck1_set1 = S5PV210_GPH0(3),
+ .buck1_set2 = S5PV210_GPH0(4),
+ .buck2_set3 = S5PV210_GPH0(5),
+ .buck1_max_voltage1 = 1200000,
+ .buck1_max_voltage2 = 1200000,
+ .buck2_max_voltage = 1200000,
};
#endif
/*
+ * Copyright (C) 2010 Magnus Damm
* Copyright (C) 2008 Renesas Solutions Corp.
*
* This program is free software; you can redistribute it and/or modify
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <mach/hardware.h>
#include <mach/irqs.h>
+#define INTCA_BASE 0xe6980000
+#define INTFLGA_OFFS 0x00000018 /* accept pending interrupt */
+#define INTEVTA_OFFS 0x00000020 /* vector number of accepted interrupt */
+#define INTLVLA_OFFS 0x00000030 /* priority level of accepted interrupt */
+#define INTLVLB_OFFS 0x00000034 /* previous priority level */
+
.macro disable_fiq
.endm
.macro get_irqnr_preamble, base, tmp
- ldr \base, =INTFLGA
+ ldr \base, =INTCA_BASE
.endm
.macro arch_ret_to_user, tmp1, tmp2
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- ldr \irqnr, [\base]
+ /* The single INTFLGA read access below results in the following:
+ *
+ * 1. INTLVLB is updated with old priority value from INTLVLA
+ * 2. Highest priority interrupt is accepted
+ * 3. INTLVLA is updated to contain priority of accepted interrupt
+ * 4. Accepted interrupt vector is stored in INTFLGA and INTEVTA
+ */
+ ldr \irqnr, [\base, #INTFLGA_OFFS]
+
+ /* Restore INTLVLA with the value saved in INTLVLB.
+ * This is required to support interrupt priorities properly.
+ */
+ ldrb \tmp, [\base, #INTLVLB_OFFS]
+ strb \tmp, [\base, #INTLVLA_OFFS]
+
+ /* Handle invalid vector number case */
cmp \irqnr, #0
beq 1000f
- /* intevt to irq number */
+
+ /* Convert vector to irq number, same as the evt2irq() macro */
lsr \irqnr, \irqnr, #0x5
subs \irqnr, \irqnr, #16
#define __ASM_MACH_VMALLOC_H
/* Vmalloc at ... - 0xe5ffffff */
-#define VMALLOC_END 0xe6000000
+#define VMALLOC_END 0xe6000000UL
#endif /* __ASM_MACH_VMALLOC_H */
*/
#include <linux/init.h>
+#include <linux/highmem.h>
#include <asm/cacheflush.h>
-#include <asm/kmap_types.h>
-#include <asm/fixmap.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
#include <plat/cache-feroceon-l2.h>
-#include "mm.h"
/*
* Low-level cache maintenance operations.
* between which we don't want to be preempted.
*/
-static inline unsigned long l2_start_va(unsigned long paddr)
+static inline unsigned long l2_get_va(unsigned long paddr)
{
#ifdef CONFIG_HIGHMEM
/*
- * Let's do our own fixmap stuff in a minimal way here.
* Because range ops can't be done on physical addresses,
* we simply install a virtual mapping for it only for the
* TLB lookup to occur, hence no need to flush the untouched
- * memory mapping. This is protected with the disabling of
- * interrupts by the caller.
+ * memory mapping afterwards (note: a cache flush may happen
+ * in some circumstances depending on the path taken in kunmap_atomic).
*/
- unsigned long idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
- unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
- set_pte_ext(TOP_PTE(vaddr), pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL), 0);
- local_flush_tlb_kernel_page(vaddr);
- return vaddr + (paddr & ~PAGE_MASK);
+ void *vaddr = kmap_atomic_pfn(paddr >> PAGE_SHIFT);
+ return (unsigned long)vaddr + (paddr & ~PAGE_MASK);
#else
return __phys_to_virt(paddr);
#endif
}
+static inline void l2_put_va(unsigned long vaddr)
+{
+#ifdef CONFIG_HIGHMEM
+ kunmap_atomic((void *)vaddr);
+#endif
+}
+
static inline void l2_clean_pa(unsigned long addr)
{
__asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr));
*/
BUG_ON((start ^ end) >> PAGE_SHIFT);
- raw_local_irq_save(flags);
- va_start = l2_start_va(start);
+ va_start = l2_get_va(start);
va_end = va_start + (end - start);
+ raw_local_irq_save(flags);
__asm__("mcr p15, 1, %0, c15, c9, 4\n\t"
"mcr p15, 1, %1, c15, c9, 5"
: : "r" (va_start), "r" (va_end));
raw_local_irq_restore(flags);
+ l2_put_va(va_start);
}
static inline void l2_clean_inv_pa(unsigned long addr)
*/
BUG_ON((start ^ end) >> PAGE_SHIFT);
- raw_local_irq_save(flags);
- va_start = l2_start_va(start);
+ va_start = l2_get_va(start);
va_end = va_start + (end - start);
+ raw_local_irq_save(flags);
__asm__("mcr p15, 1, %0, c15, c11, 4\n\t"
"mcr p15, 1, %1, c15, c11, 5"
: : "r" (va_start), "r" (va_end));
raw_local_irq_restore(flags);
+ l2_put_va(va_start);
}
static inline void l2_inv_all(void)
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
+#include <linux/highmem.h>
#include <asm/system.h>
#include <asm/cputype.h>
#include <asm/cacheflush.h>
-#include <asm/kmap_types.h>
-#include <asm/fixmap.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
-#include "mm.h"
#define CR_L2 (1 << 26)
dsb();
}
+static inline void l2_unmap_va(unsigned long va)
+{
#ifdef CONFIG_HIGHMEM
-#define l2_map_save_flags(x) raw_local_save_flags(x)
-#define l2_map_restore_flags(x) raw_local_irq_restore(x)
-#else
-#define l2_map_save_flags(x) ((x) = 0)
-#define l2_map_restore_flags(x) ((void)(x))
+ if (va != -1)
+ kunmap_atomic((void *)va);
#endif
+}
-static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va,
- unsigned long flags)
+static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va)
{
#ifdef CONFIG_HIGHMEM
unsigned long va = prev_va & PAGE_MASK;
/*
* Switching to a new page. Because cache ops are
* using virtual addresses only, we must put a mapping
- * in place for it. We also enable interrupts for a
- * short while and disable them again to protect this
- * mapping.
+ * in place for it.
*/
- unsigned long idx;
- raw_local_irq_restore(flags);
- idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
- va = __fix_to_virt(FIX_KMAP_BEGIN + idx);
- raw_local_irq_restore(flags | PSR_I_BIT);
- set_pte_ext(TOP_PTE(va), pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL), 0);
- local_flush_tlb_kernel_page(va);
+ l2_unmap_va(prev_va);
+ va = (unsigned long)kmap_atomic_pfn(pa >> PAGE_SHIFT);
}
return va + (pa_offset >> (32 - PAGE_SHIFT));
#else
static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
{
- unsigned long vaddr, flags;
+ unsigned long vaddr;
if (start == 0 && end == -1ul) {
xsc3_l2_inv_all();
}
vaddr = -1; /* to force the first mapping */
- l2_map_save_flags(flags);
/*
* Clean and invalidate partial first cache line.
*/
if (start & (CACHE_LINE_SIZE - 1)) {
- vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr, flags);
+ vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr);
xsc3_l2_clean_mva(vaddr);
xsc3_l2_inv_mva(vaddr);
start = (start | (CACHE_LINE_SIZE - 1)) + 1;
* Invalidate all full cache lines between 'start' and 'end'.
*/
while (start < (end & ~(CACHE_LINE_SIZE - 1))) {
- vaddr = l2_map_va(start, vaddr, flags);
+ vaddr = l2_map_va(start, vaddr);
xsc3_l2_inv_mva(vaddr);
start += CACHE_LINE_SIZE;
}
* Clean and invalidate partial last cache line.
*/
if (start < end) {
- vaddr = l2_map_va(start, vaddr, flags);
+ vaddr = l2_map_va(start, vaddr);
xsc3_l2_clean_mva(vaddr);
xsc3_l2_inv_mva(vaddr);
}
- l2_map_restore_flags(flags);
+ l2_unmap_va(vaddr);
dsb();
}
static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
{
- unsigned long vaddr, flags;
+ unsigned long vaddr;
vaddr = -1; /* to force the first mapping */
- l2_map_save_flags(flags);
start &= ~(CACHE_LINE_SIZE - 1);
while (start < end) {
- vaddr = l2_map_va(start, vaddr, flags);
+ vaddr = l2_map_va(start, vaddr);
xsc3_l2_clean_mva(vaddr);
start += CACHE_LINE_SIZE;
}
- l2_map_restore_flags(flags);
+ l2_unmap_va(vaddr);
dsb();
}
static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
{
- unsigned long vaddr, flags;
+ unsigned long vaddr;
if (start == 0 && end == -1ul) {
xsc3_l2_flush_all();
}
vaddr = -1; /* to force the first mapping */
- l2_map_save_flags(flags);
start &= ~(CACHE_LINE_SIZE - 1);
while (start < end) {
- vaddr = l2_map_va(start, vaddr, flags);
+ vaddr = l2_map_va(start, vaddr);
xsc3_l2_clean_mva(vaddr);
xsc3_l2_inv_mva(vaddr);
start += CACHE_LINE_SIZE;
}
- l2_map_restore_flags(flags);
+ l2_unmap_va(vaddr);
dsb();
}
#include <linux/init.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <linux/highmem.h>
#include <asm/memory.h>
#include <asm/highmem.h>
op(vaddr, len, dir);
kunmap_high(page);
} else if (cache_is_vipt()) {
- pte_t saved_pte;
- vaddr = kmap_high_l1_vipt(page, &saved_pte);
+ /* unmapped pages might still be cached */
+ vaddr = kmap_atomic(page);
op(vaddr + offset, len, dir);
- kunmap_high_l1_vipt(page, saved_pte);
+ kunmap_atomic(vaddr);
}
} else {
vaddr = page_address(page) + offset;
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
+#include <linux/highmem.h>
#include <asm/cacheflush.h>
#include <asm/cachetype.h>
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
kunmap_high(page);
} else if (cache_is_vipt()) {
- pte_t saved_pte;
- addr = kmap_high_l1_vipt(page, &saved_pte);
+ /* unmapped pages might still be cached */
+ addr = kmap_atomic(page);
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
- kunmap_high_l1_vipt(page, saved_pte);
+ kunmap_atomic(addr);
}
}
pte = TOP_PTE(vaddr);
return pte_page(*pte);
}
-
-#ifdef CONFIG_CPU_CACHE_VIPT
-
-#include <linux/percpu.h>
-
-/*
- * The VIVT cache of a highmem page is always flushed before the page
- * is unmapped. Hence unmapped highmem pages need no cache maintenance
- * in that case.
- *
- * However unmapped pages may still be cached with a VIPT cache, and
- * it is not possible to perform cache maintenance on them using physical
- * addresses unfortunately. So we have no choice but to set up a temporary
- * virtual mapping for that purpose.
- *
- * Yet this VIPT cache maintenance may be triggered from DMA support
- * functions which are possibly called from interrupt context. As we don't
- * want to keep interrupt disabled all the time when such maintenance is
- * taking place, we therefore allow for some reentrancy by preserving and
- * restoring the previous fixmap entry before the interrupted context is
- * resumed. If the reentrancy depth is 0 then there is no need to restore
- * the previous fixmap, and leaving the current one in place allow it to
- * be reused the next time without a TLB flush (common with DMA).
- */
-
-static DEFINE_PER_CPU(int, kmap_high_l1_vipt_depth);
-
-void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte)
-{
- unsigned int idx, cpu;
- int *depth;
- unsigned long vaddr, flags;
- pte_t pte, *ptep;
-
- if (!in_interrupt())
- preempt_disable();
-
- cpu = smp_processor_id();
- depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
-
- idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
- vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
- ptep = TOP_PTE(vaddr);
- pte = mk_pte(page, kmap_prot);
-
- raw_local_irq_save(flags);
- (*depth)++;
- if (pte_val(*ptep) == pte_val(pte)) {
- *saved_pte = pte;
- } else {
- *saved_pte = *ptep;
- set_pte_ext(ptep, pte, 0);
- local_flush_tlb_kernel_page(vaddr);
- }
- raw_local_irq_restore(flags);
-
- return (void *)vaddr;
-}
-
-void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte)
-{
- unsigned int idx, cpu = smp_processor_id();
- int *depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
- unsigned long vaddr, flags;
- pte_t pte, *ptep;
-
- idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
- vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
- ptep = TOP_PTE(vaddr);
- pte = mk_pte(page, kmap_prot);
-
- BUG_ON(pte_val(*ptep) != pte_val(pte));
- BUG_ON(*depth <= 0);
-
- raw_local_irq_save(flags);
- (*depth)--;
- if (*depth != 0 && pte_val(pte) != pte_val(saved_pte)) {
- set_pte_ext(ptep, saved_pte, 0);
- local_flush_tlb_kernel_page(vaddr);
- }
- raw_local_irq_restore(flags);
-
- if (!in_interrupt())
- preempt_enable();
-}
-
-#endif /* CONFIG_CPU_CACHE_VIPT */
default y
select NO_IOPORT
select ARCH_REQUIRE_GPIOLIB
- select S3C_DEVICE_NAND
+ select S3C_DEV_NAND
select S3C_GPIO_CFG_S3C24XX
help
Base platform code for any Samsung S3C24XX device
select GENERIC_ATOMIC64 if !64BIT
select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_IRQ_PROBE
menu "Machine selection"
endchoice
+config FORCE_MAX_ZONEORDER
+ int "Maximum zone order"
+ range 13 64 if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_32KB
+ default "13" if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_32KB
+ range 12 64 if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_16KB
+ default "12" if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_16KB
+ range 11 64
+ default "11"
+ help
+ The kernel memory allocator divides physically contiguous memory
+ blocks into "zones", where each zone is a power of two number of
+ pages. This option selects the largest power of two that the kernel
+ keeps in the memory allocator. If you need to allocate very large
+ blocks of physically contiguous memory, then you may need to
+ increase this value.
+
+ This config option is actually maximum order plus one. For example,
+ a value of 11 means that the largest free memory block is 2^10 pages.
+
+ The page size is not necessarily 4KB. Keep this in mind
+ when choosing a value for this option.
+
config BOARD_SCACHE
bool
bool
#
-# Use the generic interrupt handling code in kernel/irq/:
-#
-config GENERIC_HARDIRQS
- bool
- default y
-
-config GENERIC_IRQ_PROBE
- bool
- default y
-
-config IRQ_PER_CPU
- bool
-
-#
# - Highmem only makes sense for the 32-bit kernel.
# - The current highmem code will only work properly on physically indexed
# caches such as R3000, SB1, R7000 or those that look like they're virtually
static void alchemy_8250_pm(struct uart_port *port, unsigned int state,
unsigned int old_state)
{
+#ifdef CONFIG_SERIAL_8250
switch (state) {
case 0:
if ((__raw_readl(port->membase + UART_MOD_CNTRL) & 3) != 3) {
serial8250_do_pm(port, state, old_state);
break;
}
+#endif
}
#define PORT(_base, _irq) \
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
- if (!memsize_str)
+ if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize))
memsize = ALCHEMY_BOARD_DEFAULT_MEMSIZE;
- else
- strict_strtoul(memsize_str, 0, &memsize);
+
add_memory_region(0, memsize, BOOT_MEM_RAM);
}
calculate(base_clock, frequency, &prediv, &postdiv, &mul);
writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl);
- msleep(1);
+ mdelay(1);
writel(4, &clock->pll);
while (readl(&clock->pll) & PLL_STATUS)
;
writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll);
- msleep(75);
+ mdelay(75);
}
static void __init tnetd7300_init_clocks(void)
}
EXPORT_SYMBOL(clk_put);
-int __init ar7_init_clocks(void)
+void __init ar7_init_clocks(void)
{
switch (ar7_chip_id()) {
case AR7_CHIP_7100:
}
/* adjust vbus clock rate */
vbus_clk.rate = bus_clk.rate / 2;
-
- return 0;
}
-arch_initcall(ar7_init_clocks);
{
struct clk *cpu_clk;
+ /* Initialize ar7 clocks so the CPU clock frequency is correct */
+ ar7_init_clocks();
+
cpu_clk = clk_get(NULL, "cpu");
if (IS_ERR(cpu_clk)) {
printk(KERN_ERR "unable to get cpu clock\n");
#include <asm/reboot.h>
#include <asm/time.h>
#include <bcm47xx.h>
-#include <asm/fw/cfe/cfe_api.h>
#include <asm/mach-bcm47xx/nvram.h>
struct ssb_bus ssb_bcm47xx;
cpu_relax();
}
-static void str2eaddr(char *str, char *dest)
-{
- int i = 0;
+#define READ_FROM_NVRAM(_outvar, name, buf) \
+ if (nvram_getenv(name, buf, sizeof(buf)) >= 0)\
+ sprom->_outvar = simple_strtoul(buf, NULL, 0);
- if (str == NULL) {
- memset(dest, 0, 6);
- return;
+static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
+{
+ char buf[100];
+ u32 boardflags;
+
+ memset(sprom, 0, sizeof(struct ssb_sprom));
+
+ sprom->revision = 1; /* Fallback: Old hardware does not define this. */
+ READ_FROM_NVRAM(revision, "sromrev", buf);
+ if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0)
+ nvram_parse_macaddr(buf, sprom->il0mac);
+ if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
+ nvram_parse_macaddr(buf, sprom->et0mac);
+ if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
+ nvram_parse_macaddr(buf, sprom->et1mac);
+ READ_FROM_NVRAM(et0phyaddr, "et0phyaddr", buf);
+ READ_FROM_NVRAM(et1phyaddr, "et1phyaddr", buf);
+ READ_FROM_NVRAM(et0mdcport, "et0mdcport", buf);
+ READ_FROM_NVRAM(et1mdcport, "et1mdcport", buf);
+ READ_FROM_NVRAM(board_rev, "boardrev", buf);
+ READ_FROM_NVRAM(country_code, "ccode", buf);
+ READ_FROM_NVRAM(ant_available_a, "aa5g", buf);
+ READ_FROM_NVRAM(ant_available_bg, "aa2g", buf);
+ READ_FROM_NVRAM(pa0b0, "pa0b0", buf);
+ READ_FROM_NVRAM(pa0b1, "pa0b1", buf);
+ READ_FROM_NVRAM(pa0b2, "pa0b2", buf);
+ READ_FROM_NVRAM(pa1b0, "pa1b0", buf);
+ READ_FROM_NVRAM(pa1b1, "pa1b1", buf);
+ READ_FROM_NVRAM(pa1b2, "pa1b2", buf);
+ READ_FROM_NVRAM(pa1lob0, "pa1lob0", buf);
+ READ_FROM_NVRAM(pa1lob2, "pa1lob1", buf);
+ READ_FROM_NVRAM(pa1lob1, "pa1lob2", buf);
+ READ_FROM_NVRAM(pa1hib0, "pa1hib0", buf);
+ READ_FROM_NVRAM(pa1hib2, "pa1hib1", buf);
+ READ_FROM_NVRAM(pa1hib1, "pa1hib2", buf);
+ READ_FROM_NVRAM(gpio0, "wl0gpio0", buf);
+ READ_FROM_NVRAM(gpio1, "wl0gpio1", buf);
+ READ_FROM_NVRAM(gpio2, "wl0gpio2", buf);
+ READ_FROM_NVRAM(gpio3, "wl0gpio3", buf);
+ READ_FROM_NVRAM(maxpwr_bg, "pa0maxpwr", buf);
+ READ_FROM_NVRAM(maxpwr_al, "pa1lomaxpwr", buf);
+ READ_FROM_NVRAM(maxpwr_a, "pa1maxpwr", buf);
+ READ_FROM_NVRAM(maxpwr_ah, "pa1himaxpwr", buf);
+ READ_FROM_NVRAM(itssi_a, "pa1itssit", buf);
+ READ_FROM_NVRAM(itssi_bg, "pa0itssit", buf);
+ READ_FROM_NVRAM(tri2g, "tri2g", buf);
+ READ_FROM_NVRAM(tri5gl, "tri5gl", buf);
+ READ_FROM_NVRAM(tri5g, "tri5g", buf);
+ READ_FROM_NVRAM(tri5gh, "tri5gh", buf);
+ READ_FROM_NVRAM(rxpo2g, "rxpo2g", buf);
+ READ_FROM_NVRAM(rxpo5g, "rxpo5g", buf);
+ READ_FROM_NVRAM(rssisav2g, "rssisav2g", buf);
+ READ_FROM_NVRAM(rssismc2g, "rssismc2g", buf);
+ READ_FROM_NVRAM(rssismf2g, "rssismf2g", buf);
+ READ_FROM_NVRAM(bxa2g, "bxa2g", buf);
+ READ_FROM_NVRAM(rssisav5g, "rssisav5g", buf);
+ READ_FROM_NVRAM(rssismc5g, "rssismc5g", buf);
+ READ_FROM_NVRAM(rssismf5g, "rssismf5g", buf);
+ READ_FROM_NVRAM(bxa5g, "bxa5g", buf);
+ READ_FROM_NVRAM(cck2gpo, "cck2gpo", buf);
+ READ_FROM_NVRAM(ofdm2gpo, "ofdm2gpo", buf);
+ READ_FROM_NVRAM(ofdm5glpo, "ofdm5glpo", buf);
+ READ_FROM_NVRAM(ofdm5gpo, "ofdm5gpo", buf);
+ READ_FROM_NVRAM(ofdm5ghpo, "ofdm5ghpo", buf);
+
+ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0) {
+ boardflags = simple_strtoul(buf, NULL, 0);
+ if (boardflags) {
+ sprom->boardflags_lo = (boardflags & 0x0000FFFFU);
+ sprom->boardflags_hi = (boardflags & 0xFFFF0000U) >> 16;
+ }
}
-
- for (;;) {
- dest[i++] = (char) simple_strtoul(str, NULL, 16);
- str += 2;
- if (!*str++ || i == 6)
- break;
+ if (nvram_getenv("boardflags2", buf, sizeof(buf)) >= 0) {
+ boardflags = simple_strtoul(buf, NULL, 0);
+ if (boardflags) {
+ sprom->boardflags2_lo = (boardflags & 0x0000FFFFU);
+ sprom->boardflags2_hi = (boardflags & 0xFFFF0000U) >> 16;
+ }
}
}
static int bcm47xx_get_invariants(struct ssb_bus *bus,
struct ssb_init_invariants *iv)
{
- char buf[100];
+ char buf[20];
/* Fill boardinfo structure */
memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
- if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 ||
- nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
- iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
- if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 ||
- nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
+ if (nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
+ iv->boardinfo.vendor = (u16)simple_strtoul(buf, NULL, 0);
+ else
+ iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
+ if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
- if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 ||
- nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
+ if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
- /* Fill sprom structure */
- memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
- iv->sprom.revision = 3;
-
- if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 ||
- nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
- str2eaddr(buf, iv->sprom.et0mac);
+ bcm47xx_fill_sprom(&iv->sprom);
- if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 ||
- nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
- str2eaddr(buf, iv->sprom.et1mac);
-
- if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 ||
- nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
- iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0);
-
- if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 ||
- nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
- iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0);
-
- if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 ||
- nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
- iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10);
-
- if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 ||
- nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
- iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10);
+ if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
+ iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
return 0;
}
void __init plat_mem_setup(void)
{
int err;
+ char buf[100];
+ struct ssb_mipscore *mcore;
err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
bcm47xx_get_invariants);
if (err)
panic("Failed to initialize SSB bus (err %d)\n", err);
+ mcore = &ssb_bcm47xx.mipscore;
+ if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
+ if (strstr(buf, "console=ttyS1")) {
+ struct ssb_serial_port port;
+
+ printk(KERN_DEBUG "Swapping serial ports!\n");
+ /* swap serial ports */
+ memcpy(&port, &mcore->serial_ports[0], sizeof(port));
+ memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1],
+ sizeof(port));
+ memcpy(&mcore->serial_ports[1], &port, sizeof(port));
+ }
+ }
+
_machine_restart = bcm47xx_machine_restart;
_machine_halt = bcm47xx_machine_halt;
pm_power_off = bcm47xx_machine_halt;
* These are the PRID's for when 23:16 == PRID_COMP_BROADCOM
*/
-#define PRID_IMP_BMIPS4KC 0x4000
-#define PRID_IMP_BMIPS32 0x8000
+#define PRID_IMP_BMIPS32_REV4 0x4000
+#define PRID_IMP_BMIPS32_REV8 0x8000
#define PRID_IMP_BMIPS3300 0x9000
#define PRID_IMP_BMIPS3300_ALT 0x9100
#define PRID_IMP_BMIPS3300_BUG 0x0000
#define SET_PERSONALITY(ex) \
do { \
- set_personality(PER_LINUX); \
+ if (personality(current->personality) != PER_LINUX) \
+ set_personality(PER_LINUX); \
\
current->thread.abi = &mips_abi; \
} while (0)
#define SET_PERSONALITY(ex) \
do { \
+ unsigned int p; \
+ \
clear_thread_flag(TIF_32BIT_REGS); \
clear_thread_flag(TIF_32BIT_ADDR); \
\
else \
current->thread.abi = &mips_abi; \
\
- if (current->personality != PER_LINUX32) \
+ p = personality(current->personality); \
+ if (p != PER_LINUX32 && p != PER_LINUX) \
set_personality(PER_LINUX); \
} while (0)
"dsrl32 %L0, %L0, 0" "\n\t" \
"dsll32 %M0, %M0, 0" "\n\t" \
"or %L0, %L0, %M0" "\n\t" \
+ ".set push" "\n\t" \
+ ".set noreorder" "\n\t" \
+ ".set nomacro" "\n\t" \
"sd %L0, %2" "\n\t" \
+ ".set pop" "\n\t" \
".set mips0" "\n" \
: "=r" (__tmp) \
- : "0" (__val), "m" (*__mem)); \
+ : "0" (__val), "R" (*__mem)); \
if (irq) \
local_irq_restore(__flags); \
} else \
local_irq_save(__flags); \
__asm__ __volatile__( \
".set mips3" "\t\t# __readq" "\n\t" \
+ ".set push" "\n\t" \
+ ".set noreorder" "\n\t" \
+ ".set nomacro" "\n\t" \
"ld %L0, %1" "\n\t" \
+ ".set pop" "\n\t" \
"dsra32 %M0, %L0, 0" "\n\t" \
"sll %L0, %L0, 0" "\n\t" \
".set mips0" "\n" \
: "=r" (__val) \
- : "m" (*__mem)); \
+ : "R" (*__mem)); \
if (irq) \
local_irq_restore(__flags); \
} else { \
}
int __init ar7_gpio_init(void);
-
-int __init ar7_gpio_init(void);
+void __init ar7_init_clocks(void);
#endif /* __AR7_H__ */
#define __NVRAM_H
#include <linux/types.h>
+#include <linux/kernel.h>
struct nvram_header {
u32 magic;
extern int nvram_getenv(char *name, char *val, size_t val_len);
+static inline void nvram_parse_macaddr(char *buf, u8 *macaddr)
+{
+ sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1],
+ &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]);
+}
+
#endif
*
* Copyright (c) 2009 Qi Hardware inc.,
* Author: Xiangfu Liu <xiangfu@qi-hardware.com>
- * Copyright 2010, Lars-Petrer Clausen <lars@metafoo.de>
+ * Copyright 2010, Lars-Peter Clausen <lars@metafoo.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 or later
QI_LB60_GPIO_KEYIN(3),
QI_LB60_GPIO_KEYIN(4),
QI_LB60_GPIO_KEYIN(5),
- QI_LB60_GPIO_KEYIN(7),
+ QI_LB60_GPIO_KEYIN(6),
QI_LB60_GPIO_KEYIN8,
};
/* PCM */
struct platform_device jz4740_pcm_device = {
- .name = "jz4740-pcm",
+ .name = "jz4740-pcm-audio",
.id = -1,
};
#include <asm/bootinfo.h>
#include <asm/mach-jz4740/base.h>
-void jz4740_init_cmdline(int argc, char *argv[])
+static __init void jz4740_init_cmdline(int argc, char *argv[])
{
unsigned int count = COMMAND_LINE_SIZE - 1;
int i;
cnt = read_c0_count();
cnt += delta;
write_c0_compare(cnt);
- res = ((int)(read_c0_count() - cnt) > 0) ? -ETIME : 0;
+ res = ((int)(read_c0_count() - cnt) >= 0) ? -ETIME : 0;
return res;
}
{
decode_configs(c);
switch (c->processor_id & 0xff00) {
- case PRID_IMP_BMIPS32:
+ case PRID_IMP_BMIPS32_REV4:
+ case PRID_IMP_BMIPS32_REV8:
c->cputype = CPU_BMIPS32;
__cpu_name[cpu] = "Broadcom BMIPS32";
break;
__cpu_name[cpu] = "Broadcom BMIPS5000";
c->options |= MIPS_CPU_ULRI;
break;
- case PRID_IMP_BMIPS4KC:
- c->cputype = CPU_4KC;
- __cpu_name[cpu] = "MIPS 4Kc";
- break;
}
}
SYSCALL_DEFINE1(32_personality, unsigned long, personality)
{
+ unsigned int p = personality & 0xffffffff;
int ret;
- personality &= 0xffffffff;
+
if (personality(current->personality) == PER_LINUX32 &&
- personality == PER_LINUX)
- personality = PER_LINUX32;
- ret = sys_personality(personality);
- if (ret == PER_LINUX32)
- ret = PER_LINUX;
+ personality(p) == PER_LINUX)
+ p = (p & ~PER_MASK) | PER_LINUX32;
+ ret = sys_personality(p);
+ if (ret != -1 && personality(ret) == PER_LINUX32)
+ ret = (ret & ~PER_MASK) | PER_LINUX;
return ret;
}
childregs->regs[7] = 0; /* Clear error flag */
childregs->regs[2] = 0; /* Child gets zero as return value */
- regs->regs[2] = p->pid;
if (childregs->cp0_status & ST0_CU0) {
childregs->regs[28] = (unsigned long) ti;
return;
base = virt_to_phys((void *)initial_boot_params);
- size = initial_boot_params->totalsize;
+ size = be32_to_cpu(initial_boot_params->totalsize);
/* Before we do anything, lets reserve the dt blob */
reserve_mem_mach(base, size);
{
extern int gic_present;
- /* This is Malta specific: IPI,performance and timer inetrrupts */
+ /* This is Malta specific: IPI,performance and timer interrupts */
if (gic_present)
change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
STATUSF_IP6 | STATUSF_IP7);
extern asmlinkage void handle_reserved(void);
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
- struct mips_fpu_struct *ctx, int has_fpu);
+ struct mips_fpu_struct *ctx, int has_fpu,
+ void *__user *fault_addr);
void (*board_be_init)(void);
int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
force_sig_info(SIGFPE, &info, current);
}
+static int process_fpemu_return(int sig, void __user *fault_addr)
+{
+ if (sig == SIGSEGV || sig == SIGBUS) {
+ struct siginfo si = {0};
+ si.si_addr = fault_addr;
+ si.si_signo = sig;
+ if (sig == SIGSEGV) {
+ if (find_vma(current->mm, (unsigned long)fault_addr))
+ si.si_code = SEGV_ACCERR;
+ else
+ si.si_code = SEGV_MAPERR;
+ } else {
+ si.si_code = BUS_ADRERR;
+ }
+ force_sig_info(sig, &si, current);
+ return 1;
+ } else if (sig) {
+ force_sig(sig, current);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
/*
* XXX Delayed fp exceptions when doing a lazy ctx switch XXX
*/
asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
{
- siginfo_t info;
+ siginfo_t info = {0};
if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE)
== NOTIFY_STOP)
if (fcr31 & FPU_CSR_UNI_X) {
int sig;
+ void __user *fault_addr = NULL;
/*
* Unimplemented operation exception. If we've got the full
lose_fpu(1);
/* Run the emulator */
- sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1);
+ sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1,
+ &fault_addr);
/*
* We can't allow the emulated instruction to leave any of
own_fpu(1); /* Using the FPU again. */
/* If something went wrong, signal */
- if (sig)
- force_sig(sig, current);
+ process_fpemu_return(sig, fault_addr);
return;
} else if (fcr31 & FPU_CSR_INV_X)
if (!raw_cpu_has_fpu) {
int sig;
+ void __user *fault_addr = NULL;
sig = fpu_emulator_cop1Handler(regs,
- ¤t->thread.fpu, 0);
- if (sig)
- force_sig(sig, current);
- else
+ ¤t->thread.fpu,
+ 0, &fault_addr);
+ if (!process_fpemu_return(sig, fault_addr))
mt_ase_fp_affinity();
}
/* this of-course trashes what was there before... */
v->pbuffer = vmalloc(P_SIZE);
+ if (!v->pbuffer) {
+ pr_warning("VPE loader: unable to allocate memory\n");
+ return -ENOMEM;
+ }
v->plen = P_SIZE;
v->load_addr = NULL;
v->len = 0;
if (ret < 0)
v->shared_ptr = NULL;
- // cleanup any temp buffers
- if (v->pbuffer)
- vfree(v->pbuffer);
+ vfree(v->pbuffer);
v->plen = 0;
+
return ret;
}
if (v == NULL)
return -ENODEV;
- if (v->pbuffer == NULL) {
- printk(KERN_ERR "VPE loader: no buffer for program\n");
- return -ENOMEM;
- }
-
if ((count + v->len) > v->plen) {
printk(KERN_WARNING
"VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
.Lfwd_fixup:
PTR_L t0, TI_TASK($28)
- LONG_L t0, THREAD_BUADDR(t0)
andi a2, 0x3f
+ LONG_L t0, THREAD_BUADDR(t0)
LONG_ADDU a2, t1
jr ra
LONG_SUBU a2, t0
.Lpartial_fixup:
PTR_L t0, TI_TASK($28)
- LONG_L t0, THREAD_BUADDR(t0)
andi a2, LONGMASK
+ LONG_L t0, THREAD_BUADDR(t0)
LONG_ADDU a2, t1
jr ra
LONG_SUBU a2, t0
#define parse_even_earlier(res, option, p) \
do { \
+ int ret; \
if (strncmp(option, (char *)p, strlen(option)) == 0) \
- strict_strtol((char *)p + strlen(option"="), \
- 10, &res); \
+ ret = strict_strtol((char *)p + strlen(option"="), 10, &res); \
} while (0)
void __init prom_init_env(void)
#if __mips >= 4 && __mips != 32
static int fpux_emu(struct pt_regs *,
- struct mips_fpu_struct *, mips_instruction);
+ struct mips_fpu_struct *, mips_instruction, void *__user *);
#endif
/* Further private data for which no space exists in mips_fpu_struct */
* Two instructions if the instruction is in a branch delay slot.
*/
-static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
+static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
+ void *__user *fault_addr)
{
mips_instruction ir;
unsigned long emulpc, contpc;
unsigned int cond;
- if (get_user(ir, (mips_instruction __user *) xcp->cp0_epc)) {
+ if (!access_ok(VERIFY_READ, xcp->cp0_epc, sizeof(mips_instruction))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = (mips_instruction __user *)xcp->cp0_epc;
return SIGBUS;
}
+ if (__get_user(ir, (mips_instruction __user *) xcp->cp0_epc)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = (mips_instruction __user *)xcp->cp0_epc;
+ return SIGSEGV;
+ }
/* XXX NEC Vr54xx bug workaround */
if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
#endif
return SIGILL;
}
- if (get_user(ir, (mips_instruction __user *) emulpc)) {
+ if (!access_ok(VERIFY_READ, emulpc, sizeof(mips_instruction))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = (mips_instruction __user *)emulpc;
return SIGBUS;
}
+ if (__get_user(ir, (mips_instruction __user *) emulpc)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = (mips_instruction __user *)emulpc;
+ return SIGSEGV;
+ }
/* __compute_return_epc() will have updated cp0_epc */
contpc = xcp->cp0_epc;
/* In order not to confuse ptrace() et al, tweak context */
u64 val;
MIPS_FPU_EMU_INC_STATS(loads);
- if (get_user(val, va)) {
+
+ if (!access_ok(VERIFY_READ, va, sizeof(u64))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
return SIGBUS;
}
+ if (__get_user(val, va)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
+ return SIGSEGV;
+ }
DITOREG(val, MIPSInst_RT(ir));
break;
}
MIPS_FPU_EMU_INC_STATS(stores);
DIFROMREG(val, MIPSInst_RT(ir));
- if (put_user(val, va)) {
+ if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
return SIGBUS;
}
+ if (__put_user(val, va)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
+ return SIGSEGV;
+ }
break;
}
u32 val;
MIPS_FPU_EMU_INC_STATS(loads);
- if (get_user(val, va)) {
+ if (!access_ok(VERIFY_READ, va, sizeof(u32))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
return SIGBUS;
}
+ if (__get_user(val, va)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
+ return SIGSEGV;
+ }
SITOREG(val, MIPSInst_RT(ir));
break;
}
MIPS_FPU_EMU_INC_STATS(stores);
SIFROMREG(val, MIPSInst_RT(ir));
- if (put_user(val, va)) {
+ if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
return SIGBUS;
}
+ if (__put_user(val, va)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
+ return SIGSEGV;
+ }
break;
}
contpc = (xcp->cp0_epc +
(MIPSInst_SIMM(ir) << 2));
- if (get_user(ir,
- (mips_instruction __user *) xcp->cp0_epc)) {
+ if (!access_ok(VERIFY_READ, xcp->cp0_epc,
+ sizeof(mips_instruction))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = (mips_instruction __user *)xcp->cp0_epc;
return SIGBUS;
}
+ if (__get_user(ir,
+ (mips_instruction __user *) xcp->cp0_epc)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = (mips_instruction __user *)xcp->cp0_epc;
+ return SIGSEGV;
+ }
switch (MIPSInst_OPCODE(ir)) {
case lwc1_op:
#if __mips >= 4 && __mips != 32
case cop1x_op:{
- int sig;
-
- if ((sig = fpux_emu(xcp, ctx, ir)))
+ int sig = fpux_emu(xcp, ctx, ir, fault_addr);
+ if (sig)
return sig;
break;
}
DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- mips_instruction ir)
+ mips_instruction ir, void *__user *fault_addr)
{
unsigned rcsr = 0; /* resulting csr */
xcp->regs[MIPSInst_FT(ir)]);
MIPS_FPU_EMU_INC_STATS(loads);
- if (get_user(val, va)) {
+ if (!access_ok(VERIFY_READ, va, sizeof(u32))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
return SIGBUS;
}
+ if (__get_user(val, va)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
+ return SIGSEGV;
+ }
SITOREG(val, MIPSInst_FD(ir));
break;
MIPS_FPU_EMU_INC_STATS(stores);
SIFROMREG(val, MIPSInst_FS(ir));
- if (put_user(val, va)) {
+ if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
return SIGBUS;
}
+ if (put_user(val, va)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
+ return SIGSEGV;
+ }
break;
case madd_s_op:
xcp->regs[MIPSInst_FT(ir)]);
MIPS_FPU_EMU_INC_STATS(loads);
- if (get_user(val, va)) {
+ if (!access_ok(VERIFY_READ, va, sizeof(u64))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
return SIGBUS;
}
+ if (__get_user(val, va)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
+ return SIGSEGV;
+ }
DITOREG(val, MIPSInst_FD(ir));
break;
MIPS_FPU_EMU_INC_STATS(stores);
DIFROMREG(val, MIPSInst_FS(ir));
- if (put_user(val, va)) {
+ if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
return SIGBUS;
}
+ if (__put_user(val, va)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = va;
+ return SIGSEGV;
+ }
break;
case madd_d_op:
}
int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- int has_fpu)
+ int has_fpu, void *__user *fault_addr)
{
unsigned long oldepc, prevepc;
mips_instruction insn;
do {
prevepc = xcp->cp0_epc;
- if (get_user(insn, (mips_instruction __user *) xcp->cp0_epc)) {
+ if (!access_ok(VERIFY_READ, xcp->cp0_epc, sizeof(mips_instruction))) {
MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = (mips_instruction __user *)xcp->cp0_epc;
return SIGBUS;
}
+ if (__get_user(insn, (mips_instruction __user *) xcp->cp0_epc)) {
+ MIPS_FPU_EMU_INC_STATS(errors);
+ *fault_addr = (mips_instruction __user *)xcp->cp0_epc;
+ return SIGSEGV;
+ }
if (insn == 0)
xcp->cp0_epc += 4; /* skip nops */
else {
*/
/* convert to ieee library modes */
ieee754_csr.rm = ieee_rm[ieee754_csr.rm];
- sig = cop1Emulate(xcp, ctx);
+ sig = cop1Emulate(xcp, ctx, fault_addr);
/* revert to mips rounding mode */
ieee754_csr.rm = mips_rm[ieee754_csr.rm];
}
return plat_dma_supported(dev, mask);
}
-void mips_dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction)
{
BUG_ON(direction == DMA_NONE);
__dma_sync((unsigned long)vaddr, size, direction);
}
+EXPORT_SYMBOL(dma_cache_sync);
+
static struct dma_map_ops mips_default_dma_map_ops = {
.alloc_coherent = mips_dma_alloc_coherent,
.free_coherent = mips_dma_free_coherent,
*/
static inline int mips_sc_is_activated(struct cpuinfo_mips *c)
{
+ unsigned int config2 = read_c0_config2();
+ unsigned int tmp;
+
/* Check the bypass bit (L2B) */
switch (c->cputype) {
case CPU_34K:
c->scache.linesz = 2 << tmp;
else
return 0;
+ return 1;
}
static inline int __init mips_sc_probe(void)
__asm__ __volatile__ (
" .set mips3 \n"
+ " .set push \n"
+ " .set noreorder \n"
+ " .set nomacro \n"
" ld %0, %1 \n"
+ " .set pop \n"
" lbu %0, (%0) \n"
" .set mips0 \n"
: "=r" (res)
- : "m" (vaddr));
+ : "R" (vaddr));
write_c0_status(sr);
ssnop_4();
__asm__ __volatile__ (
" .set mips3 \n"
+ " .set push \n"
+ " .set noreorder \n"
+ " .set nomacro \n"
" ld %0, %1 \n"
+ " .set pop \n"
" sb %2, (%0) \n"
" .set mips0 \n"
: "=&r" (tmp)
- : "m" (vaddr), "r" (c));
+ : "R" (vaddr), "r" (c));
write_c0_status(sr);
ssnop_4();
enum swarm_rtc_type {
RTC_NONE,
RTC_XICOR,
- RTC_M4LT81
+ RTC_M41T81,
};
enum swarm_rtc_type swarm_rtc_type;
sec = xicor_get_time();
break;
- case RTC_M4LT81:
+ case RTC_M41T81:
sec = m41t81_get_time();
break;
case RTC_XICOR:
return xicor_set_time(sec);
- case RTC_M4LT81:
+ case RTC_M41T81:
return m41t81_set_time(sec);
case RTC_NONE:
if (xicor_probe())
swarm_rtc_type = RTC_XICOR;
if (m41t81_probe())
- swarm_rtc_type = RTC_M4LT81;
+ swarm_rtc_type = RTC_M41T81;
#ifdef CONFIG_VT
screen_info = (struct screen_info) {
tmp = CROSS_GxICR(irq, new);
x &= GxICR_LEVEL | GxICR_ENABLE;
- if (GxICR(irq) & GxICR_REQUEST) {
+ if (GxICR(irq) & GxICR_REQUEST)
x |= GxICR_REQUEST | GxICR_DETECT;
CROSS_GxICR(irq, new) = x;
tmp = CROSS_GxICR(irq, new);
unsigned long long ll;
unsigned l[2];
} tsc64, result;
- unsigned long tsc, tmp;
+ unsigned long tmp;
unsigned product[3]; /* 96-bit intermediate value */
/* cnt32_to_63() is not safe with preemption */
preempt_disable();
- /* read the TSC value
- */
- tsc = get_cycles();
-
- /* expand to 64-bits.
+ /* expand the tsc to 64-bits.
* - sched_clock() must be called once a minute or better or the
* following will go horribly wrong - see cnt32_to_63()
*/
- tsc64.ll = cnt32_to_63(tsc) & 0x7fffffffffffffffULL;
+ tsc64.ll = cnt32_to_63(get_cycles()) & 0x7fffffffffffffffULL;
preempt_enable();
#include <linux/of_gpio.h>
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/fs.h>
#include <linux/watchdog.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
make_se7206_irq(IRQ1_IRQ); /* ATA */
make_se7206_irq(IRQ3_IRQ); /* SLOT / PCM */
- __raw_writew(__raw_readw(INTC_ICR1) | 0x000b, INTC_ICR); /* ICR1 */
+ __raw_writew(__raw_readw(INTC_ICR1) | 0x000b, INTC_ICR1); /* ICR1 */
/* FPGA System register setup*/
__raw_writew(0x0000,INTSTS0); /* Clear INTSTS0 */
static void master_clk_init(struct clk *clk)
{
- return 10000000 * PLL2 * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
+ clk->rate = 10000000 * PLL2 * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
}
static struct clk_ops sh7201_master_clk_ops = {
for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) {
int divisor = frqcr3_divisors[i];
- if (clk->ops->set_rate(clk, clk->parent->rate /
- divisor, 0) == 0)
+ if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0)
break;
}
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
struct pt_regs;
-int restore_sigcontext(struct pt_regs *, struct sigcontext __user *, long *);
+int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
int setup_sigcontext(struct sigcontext __user *, struct pt_regs *);
void do_signal(struct pt_regs *regs);
#endif
return ret;
}
+/* The assembly shim for this function arranges to ignore the return value. */
long compat_sys_rt_sigreturn(struct pt_regs *regs)
{
struct compat_rt_sigframe __user *frame =
(struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
sigset_t set;
- long r0;
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
- if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
goto badframe;
- return r0;
+ return 0;
badframe:
force_sig(SIGSEGV, current);
lw r20, r20
/* Jump to syscall handler. */
- jalr r20; .Lhandle_syscall_link:
- FEEDBACK_REENTER(handle_syscall)
+ jalr r20
+.Lhandle_syscall_link: /* value of "lr" after "jalr r20" above */
/*
* Write our r0 onto the stack so it gets restored instead
PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
sw r29, r0
+.Lsyscall_sigreturn_skip:
+ FEEDBACK_REENTER(handle_syscall)
+
/* Do syscall trace again, if requested. */
lw r30, r31
andi r30, r30, _TIF_SYSCALL_TRACE
}; \
STD_ENDPROC(_##x)
+/*
+ * Special-case sigreturn to not write r0 to the stack on return.
+ * This is technically more efficient, but it also avoids difficulties
+ * in the 64-bit OS when handling 32-bit compat code, since we must not
+ * sign-extend r0 for the sigreturn return-value case.
+ */
+#define PTREGS_SYSCALL_SIGRETURN(x, reg) \
+ STD_ENTRY(_##x); \
+ addli lr, lr, .Lsyscall_sigreturn_skip - .Lhandle_syscall_link; \
+ { \
+ PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
+ j x \
+ }; \
+ STD_ENDPROC(_##x)
+
PTREGS_SYSCALL(sys_execve, r3)
PTREGS_SYSCALL(sys_sigaltstack, r2)
-PTREGS_SYSCALL(sys_rt_sigreturn, r0)
+PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1)
/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
childregs->sp = sp; /* override with new user stack pointer */
/*
+ * If CLONE_SETTLS is set, set "tp" in the new task to "r4",
+ * which is passed in as arg #5 to sys_clone().
+ */
+ if (clone_flags & CLONE_SETTLS)
+ childregs->tp = regs->regs[4];
+
+ /*
* Copy the callee-saved registers from the passed pt_regs struct
* into the context-switch callee-saved registers area.
* This way when we start the interrupt-return sequence, the
return __switch_to(prev, next, next_current_ksp0(next));
}
+/* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
void __user *, parent_tidptr, void __user *, child_tidptr,
struct pt_regs *, regs)
*/
int restore_sigcontext(struct pt_regs *regs,
- struct sigcontext __user *sc, long *pr0)
+ struct sigcontext __user *sc)
{
int err = 0;
int i;
regs->faultnum = INT_SWINT_1_SIGRETURN;
- err |= __get_user(*pr0, &sc->gregs[0]);
return err;
}
-/* sigreturn() returns long since it restores r0 in the interrupted code. */
+/* The assembly shim for this function arranges to ignore the return value. */
SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
{
struct rt_sigframe __user *frame =
(struct rt_sigframe __user *)(regs->sp);
sigset_t set;
- long r0;
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
- if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
goto badframe;
- return r0;
+ return 0;
badframe:
force_sig(SIGSEGV, current);
if (heap > 0x3fffffffffffUL)
error("Destination address too large");
#else
- if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff))
+ if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
error("Destination address too large");
#endif
#ifndef CONFIG_RELOCATABLE
#define BIOS_BEGIN 0x000a0000
#define BIOS_END 0x00100000
+#define BIOS_ROM_BASE 0xffe00000
+#define BIOS_ROM_END 0xffffffff
+
#ifdef __KERNEL__
/* see comment in arch/x86/kernel/e820.c */
extern struct e820map e820;
#define KVM_NUM_MMU_PAGES (1 << KVM_MMU_HASH_SHIFT)
#define KVM_MIN_FREE_MMU_PAGES 5
#define KVM_REFILL_PAGES 25
-#define KVM_MAX_CPUID_ENTRIES 40
+#define KVM_MAX_CPUID_ENTRIES 80
#define KVM_NR_FIXED_MTRR_REGION 88
#define KVM_NR_VAR_MTRR 8
obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
obj-y += tsc.o io_delay.o rtc.o
obj-y += pci-iommu_table.o
+obj-y += resource.o
obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
obj-y += process.o
setup_apic_nmi_watchdog(NULL);
apic_pm_activate();
+
+ /*
+ * Now that local APIC setup is completed for BP, configure the fault
+ * handling for interrupt remapping.
+ */
+ if (!smp_processor_id() && intr_remapping_enabled)
+ enable_drhd_fault_handling();
+
}
#ifdef CONFIG_X86_X2APIC
{
struct irq_cfg *cfg = data->chip_data;
int i, do_unmask_irq = 0, irq = data->irq;
- struct irq_desc *desc = irq_to_desc(irq);
unsigned long v;
irq_complete_move(cfg);
#ifdef CONFIG_GENERIC_PENDING_IRQ
/* If we are moving the irq we need to mask it */
- if (unlikely(desc->status & IRQ_MOVE_PENDING)) {
+ if (unlikely(irq_to_desc(irq)->status & IRQ_MOVE_PENDING)) {
do_unmask_irq = 1;
mask_ioapic(cfg);
}
msg.data |= MSI_DATA_VECTOR(cfg->vector);
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+ msg.address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(dest);
dmar_msi_write(irq, &msg);
/* need to update phys_pkg_id */
apic->phys_pkg_id = apicid_phys_pkg_id;
}
-
- /*
- * Now that apic routing model is selected, configure the
- * fault handling for intr remapping.
- */
- if (intr_remapping_enabled)
- enable_drhd_fault_handling();
}
/* Same for both flat and physical. */
#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD)
#endif
+/* Number of possible pages in the lowmem region */
+LOWMEM_PAGES = (((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT)
+
/* Enough space to fit pagetables for the low memory linear map */
-MAPPING_BEYOND_END = \
- PAGE_TABLE_SIZE(((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT) << PAGE_SHIFT
+MAPPING_BEYOND_END = PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT
/*
* Worst-case size of the kernel mapping we need to make:
- * the worst-case size of the kernel itself, plus the extra we need
- * to map for the linear map.
+ * a relocatable kernel can live anywhere in lowmem, so we need to be able
+ * to map all of lowmem.
*/
-KERNEL_PAGES = (KERNEL_IMAGE_SIZE + MAPPING_BEYOND_END)>>PAGE_SHIFT
+KERNEL_PAGES = LOWMEM_PAGES
INIT_MAP_SIZE = PAGE_TABLE_SIZE(KERNEL_PAGES) * PAGE_SIZE_asm
RESERVE_BRK(pagetables, INIT_MAP_SIZE)
#define HPET_DEV_FSB_CAP 0x1000
#define HPET_DEV_PERI_CAP 0x2000
+#define HPET_MIN_CYCLES 128
+#define HPET_MIN_PROG_DELTA (HPET_MIN_CYCLES + (HPET_MIN_CYCLES >> 1))
+
#define EVT_TO_HPET_DEV(evt) container_of(evt, struct hpet_dev, evt)
/*
/* Calculate the min / max delta */
hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
&hpet_clockevent);
- /* 5 usec minimum reprogramming delta. */
- hpet_clockevent.min_delta_ns = 5000;
+ /* Setup minimum reprogramming delta. */
+ hpet_clockevent.min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA,
+ &hpet_clockevent);
/*
* Start hpet with the boot cpu mask and make it
* the wraparound into account) nor a simple count down event
* mode. Further the write to the comparator register is
* delayed internally up to two HPET clock cycles in certain
- * chipsets (ATI, ICH9,10). We worked around that by reading
- * back the compare register, but that required another
- * workaround for ICH9,10 chips where the first readout after
- * write can return the old stale value. We already have a
- * minimum delta of 5us enforced, but a NMI or SMI hitting
+ * chipsets (ATI, ICH9,10). Some newer AMD chipsets have even
+ * longer delays. We worked around that by reading back the
+ * compare register, but that required another workaround for
+ * ICH9,10 chips where the first readout after write can
+ * return the old stale value. We already had a minimum
+ * programming delta of 5us enforced, but a NMI or SMI hitting
* between the counter readout and the comparator write can
* move us behind that point easily. Now instead of reading
* the compare register back several times, we make the ETIME
* decision based on the following: Return ETIME if the
- * counter value after the write is less than 8 HPET cycles
+ * counter value after the write is less than HPET_MIN_CYCLES
* away from the event or if the counter is already ahead of
- * the event.
+ * the event. The minimum programming delta for the generic
+ * clockevents code is set to 1.5 * HPET_MIN_CYCLES.
*/
res = (s32)(cnt - hpet_readl(HPET_COUNTER));
- return res < 8 ? -ETIME : 0;
+ return res < HPET_MIN_CYCLES ? -ETIME : 0;
}
static void hpet_legacy_set_mode(enum clock_event_mode mode,
/* For performance reasons, reuse mc area when possible */
if (!mc || mc_size > curr_mc_size) {
- if (mc)
- vfree(mc);
+ vfree(mc);
mc = vmalloc(mc_size);
if (!mc)
break;
if (get_ucode_data(mc, ucode_ptr, mc_size) ||
microcode_sanity_check(mc) < 0) {
- vfree(mc);
break;
}
if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
- if (new_mc)
- vfree(new_mc);
+ vfree(new_mc);
new_rev = mc_header.rev;
new_mc = mc;
mc = NULL; /* trigger new vmalloc */
leftover -= mc_size;
}
- if (mc)
- vfree(mc);
+ vfree(mc);
if (leftover) {
- if (new_mc)
- vfree(new_mc);
+ vfree(new_mc);
state = UCODE_ERROR;
goto out;
}
goto out;
}
- if (uci->mc)
- vfree(uci->mc);
+ vfree(uci->mc);
uci->mc = (struct microcode_intel *)new_mc;
pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
--- /dev/null
+#include <linux/ioport.h>
+#include <asm/e820.h>
+
+static void resource_clip(struct resource *res, resource_size_t start,
+ resource_size_t end)
+{
+ resource_size_t low = 0, high = 0;
+
+ if (res->end < start || res->start > end)
+ return; /* no conflict */
+
+ if (res->start < start)
+ low = start - res->start;
+
+ if (res->end > end)
+ high = res->end - end;
+
+ /* Keep the area above or below the conflict, whichever is larger */
+ if (low > high)
+ res->end = start - 1;
+ else
+ res->start = end + 1;
+}
+
+static void remove_e820_regions(struct resource *avail)
+{
+ int i;
+ struct e820entry *entry;
+
+ for (i = 0; i < e820.nr_map; i++) {
+ entry = &e820.map[i];
+
+ resource_clip(avail, entry->addr,
+ entry->addr + entry->size - 1);
+ }
+}
+
+void arch_remove_reservations(struct resource *avail)
+{
+ /* Trim out BIOS areas (low 1MB and high 2MB) and E820 regions */
+ if (avail->flags & IORESOURCE_MEM) {
+ if (avail->start < BIOS_END)
+ avail->start = BIOS_END;
+ resource_clip(avail, BIOS_ROM_BASE, BIOS_ROM_END);
+
+ remove_e820_regions(avail);
+ }
+}
return total << PAGE_SHIFT;
}
-#define DEFAULT_BZIMAGE_ADDR_MAX 0x37FFFFFF
+/*
+ * Keep the crash kernel below this limit. On 32 bits earlier kernels
+ * would limit the kernel to the low 512 MiB due to mapping restrictions.
+ * On 64 bits, kexec-tools currently limits us to 896 MiB; increase this
+ * limit once kexec-tools are fixed.
+ */
+#ifdef CONFIG_X86_32
+# define CRASH_KERNEL_ADDR_MAX (512 << 20)
+#else
+# define CRASH_KERNEL_ADDR_MAX (896 << 20)
+#endif
+
static void __init reserve_crashkernel(void)
{
unsigned long long total_mem;
const unsigned long long alignment = 16<<20; /* 16M */
/*
- * kexec want bzImage is below DEFAULT_BZIMAGE_ADDR_MAX
+ * kexec want bzImage is below CRASH_KERNEL_ADDR_MAX
*/
crash_base = memblock_find_in_range(alignment,
- DEFAULT_BZIMAGE_ADDR_MAX, crash_size, alignment);
+ CRASH_KERNEL_ADDR_MAX, crash_size, alignment);
if (crash_base == MEMBLOCK_ERROR) {
pr_info("crashkernel reservation failed - No suitable area found.\n");
x86_init.oem.arch_setup();
- resource_alloc_from_bottom = 0;
iomem_resource.end = (1ULL << boot_cpu_data.x86_phys_bits) - 1;
setup_memory_map();
parse_setup_data();
* Setup init_xstate_buf to represent the init state of
* all the features managed by the xsave
*/
- init_xstate_buf = alloc_bootmem(xstate_size);
+ init_xstate_buf = alloc_bootmem_align(xstate_size,
+ __alignof__(struct xsave_struct));
init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
clts();
s->pics[1].elcr_mask = 0xde;
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
+ s->pics[0].isr_ack = 0xff;
+ s->pics[1].isr_ack = 0xff;
/*
* Initialize PIO device
ASSERT(!VALID_PAGE(root));
spin_lock(&vcpu->kvm->mmu_lock);
kvm_mmu_free_some_pages(vcpu);
- sp = kvm_mmu_get_page(vcpu, i << 30, i << 30,
+ sp = kvm_mmu_get_page(vcpu, i << (30 - PAGE_SHIFT),
+ i << 30,
PT32_ROOT_LEVEL, 1, ACC_ALL,
NULL);
root = __pa(sp->spt);
static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
{
switch (func) {
+ case 0x00000001:
+ /* Mask out xsave bit as long as it is not supported by SVM */
+ entry->ecx &= ~(bit(X86_FEATURE_XSAVE));
+ break;
case 0x80000001:
if (nested)
entry->ecx |= (1 << 2); /* Set SVM bit */
return PT_PDPE_LEVEL;
}
-static inline u32 bit(int bitno)
-{
- return 1 << (bitno & 31);
-}
-
static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best;
u64 __read_mostly host_xcr0;
-static inline u32 bit(int bitno)
-{
- return 1 << (bitno & 31);
-}
-
static void kvm_on_user_return(struct user_return_notifier *urn)
{
unsigned slot;
#ifdef CONFIG_CPU_FREQ
struct cpufreq_policy policy;
memset(&policy, 0, sizeof(policy));
- cpufreq_get_policy(&policy, get_cpu());
+ cpu = get_cpu();
+ cpufreq_get_policy(&policy, cpu);
if (policy.cpuinfo.max_freq)
max_tsc_khz = policy.cpuinfo.max_freq;
+ put_cpu();
#endif
cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
+ if (sregs->cr4 & X86_CR4_OSXSAVE)
+ update_cpuid(vcpu);
if (!is_long_mode(vcpu) && is_pae(vcpu)) {
load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3);
mmu_reset_needed = 1;
return kvm_read_cr0_bits(vcpu, X86_CR0_PG);
}
+static inline u32 bit(int bitno)
+{
+ return 1 << (bitno & 31);
+}
+
void kvm_before_handle_nmi(struct kvm_vcpu *vcpu);
void kvm_after_handle_nmi(struct kvm_vcpu *vcpu);
int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq);
return 0;
}
-/* initialize the APIC for the IBS interrupts if available */
+/*
+ * check and reserve APIC extended interrupt LVT offset for IBS if
+ * available
+ *
+ * init_ibs() preforms implicitly cpu-local operations, so pin this
+ * thread to its current CPU
+ */
+
static void init_ibs(void)
{
- ibs_caps = get_ibs_caps();
+ preempt_disable();
+ ibs_caps = get_ibs_caps();
if (!ibs_caps)
- return;
+ goto out;
- if (__init_ibs_nmi()) {
+ if (__init_ibs_nmi() < 0)
ibs_caps = 0;
- return;
- }
+ else
+ printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);
- printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n",
- (unsigned)ibs_caps);
+out:
+ preempt_enable();
}
static int (*create_arch_files)(struct super_block *sb, struct dentry *root);
resource_size_t size, resource_size_t align)
{
struct pci_dev *dev = data;
- resource_size_t start = round_down(res->end - size + 1, align);
+ resource_size_t start = res->start;
if (res->flags & IORESOURCE_IO) {
-
- /*
- * If we're avoiding ISA aliases, the largest contiguous I/O
- * port space is 256 bytes. Clearing bits 9 and 10 preserves
- * all 256-byte and smaller alignments, so the result will
- * still be correctly aligned.
- */
- if (!skip_isa_ioresource_align(dev))
- start &= ~0x300;
- } else if (res->flags & IORESOURCE_MEM) {
- if (start < BIOS_END)
- start = res->end; /* fail; no space */
+ if (skip_isa_ioresource_align(dev))
+ return start;
+ if (start & 0x300)
+ start = (start + 0x3ff) & ~0x3ff;
}
return start;
}
export CPPFLAGS_vdso.lds += -P -C
-VDSO_LDFLAGS_vdso.lds = -m elf_x86_64 -Wl,-soname=linux-vdso.so.1 \
+VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
-Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
$(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so
vdso32-images = $(vdso32.so-y:%=vdso32-%.so)
CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds)
-VDSO_LDFLAGS_vdso32.lds = -m elf_i386 -Wl,-soname=linux-gate.so.1
+VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-soname=linux-gate.so.1
# This makes sure the $(obj) subdirectory exists even though vdso32/
# is not a kbuild sub-make subdirectory.
for (i = 0; i < iov_count; i++) {
unsigned long uaddr = (unsigned long)iov[i].iov_base;
+ if (!iov[i].iov_len)
+ return -EINVAL;
+
if (uaddr & queue_dma_alignment(q)) {
unaligned = 1;
break;
}
- if (!iov[i].iov_len)
- return -EINVAL;
}
if (unaligned || (q->dma_pad_mask & len) || map_data)
return 0;
fbio = bio;
- cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+ cluster = blk_queue_cluster(q);
seg_size = 0;
nr_phys_segs = 0;
for_each_bio(bio) {
static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
struct bio *nxt)
{
- if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
+ if (!blk_queue_cluster(q))
return 0;
if (bio->bi_seg_back_size + nxt->bi_seg_front_size >
int nsegs, cluster;
nsegs = 0;
- cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+ cluster = blk_queue_cluster(q);
/*
* for each bio in rq
lim->alignment_offset = 0;
lim->io_opt = 0;
lim->misaligned = 0;
- lim->no_cluster = 0;
+ lim->cluster = 1;
}
EXPORT_SYMBOL(blk_set_default_limits);
EXPORT_SYMBOL(blk_queue_bounce_limit);
/**
- * blk_queue_max_hw_sectors - set max sectors for a request for this queue
- * @q: the request queue for the device
+ * blk_limits_max_hw_sectors - set hard and soft limit of max sectors for request
+ * @limits: the queue limits
* @max_hw_sectors: max hardware sectors in the usual 512b unit
*
* Description:
* per-device basis in /sys/block/<device>/queue/max_sectors_kb.
* The soft limit can not exceed max_hw_sectors.
**/
-void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors)
+void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_sectors)
{
if ((max_hw_sectors << 9) < PAGE_CACHE_SIZE) {
max_hw_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
__func__, max_hw_sectors);
}
- q->limits.max_hw_sectors = max_hw_sectors;
- q->limits.max_sectors = min_t(unsigned int, max_hw_sectors,
- BLK_DEF_MAX_SECTORS);
+ limits->max_hw_sectors = max_hw_sectors;
+ limits->max_sectors = min_t(unsigned int, max_hw_sectors,
+ BLK_DEF_MAX_SECTORS);
+}
+EXPORT_SYMBOL(blk_limits_max_hw_sectors);
+
+/**
+ * blk_queue_max_hw_sectors - set max sectors for a request for this queue
+ * @q: the request queue for the device
+ * @max_hw_sectors: max hardware sectors in the usual 512b unit
+ *
+ * Description:
+ * See description for blk_limits_max_hw_sectors().
+ **/
+void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors)
+{
+ blk_limits_max_hw_sectors(&q->limits, max_hw_sectors);
}
EXPORT_SYMBOL(blk_queue_max_hw_sectors);
void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
{
blk_stack_limits(&t->limits, &b->limits, 0);
-
- if (!t->queue_lock)
- WARN_ON_ONCE(1);
- else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) {
- unsigned long flags;
- spin_lock_irqsave(t->queue_lock, flags);
- queue_flag_clear(QUEUE_FLAG_CLUSTER, t);
- spin_unlock_irqrestore(t->queue_lock, flags);
- }
}
EXPORT_SYMBOL(blk_queue_stack_limits);
t->io_min = max(t->io_min, b->io_min);
t->io_opt = lcm(t->io_opt, b->io_opt);
- t->no_cluster |= b->no_cluster;
+ t->cluster &= b->cluster;
t->discard_zeroes_data &= b->discard_zeroes_data;
/* Physical block size a multiple of the logical block size? */
sector_t offset)
{
struct request_queue *t = disk->queue;
- struct request_queue *b = bdev_get_queue(bdev);
if (bdev_stack_limits(&t->limits, bdev, offset >> 9) < 0) {
char top[BDEVNAME_SIZE], bottom[BDEVNAME_SIZE];
printk(KERN_NOTICE "%s: Warning: Device %s is misaligned\n",
top, bottom);
}
-
- if (!t->queue_lock)
- WARN_ON_ONCE(1);
- else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) {
- unsigned long flags;
-
- spin_lock_irqsave(t->queue_lock, flags);
- if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags))
- queue_flag_clear(QUEUE_FLAG_CLUSTER, t);
- spin_unlock_irqrestore(t->queue_lock, flags);
- }
}
EXPORT_SYMBOL(disk_stack_limits);
static ssize_t queue_max_segment_size_show(struct request_queue *q, char *page)
{
- if (test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
+ if (blk_queue_cluster(q))
return queue_var_show(queue_max_segment_size(q), (page));
return queue_var_show(PAGE_CACHE_SIZE, (page));
tg->slice_end[rw], jiffies);
}
+static inline void throtl_set_slice_end(struct throtl_data *td,
+ struct throtl_grp *tg, bool rw, unsigned long jiffy_end)
+{
+ tg->slice_end[rw] = roundup(jiffy_end, throtl_slice);
+}
+
static inline void throtl_extend_slice(struct throtl_data *td,
struct throtl_grp *tg, bool rw, unsigned long jiffy_end)
{
if (throtl_slice_used(td, tg, rw))
return;
+ /*
+ * A bio has been dispatched. Also adjust slice_end. It might happen
+ * that initially cgroup limit was very low resulting in high
+ * slice_end, but later limit was bumped up and bio was dispached
+ * sooner, then we need to reduce slice_end. A high bogus slice_end
+ * is bad because it does not allow new slice to start.
+ */
+
+ throtl_set_slice_end(td, tg, rw, jiffies + throtl_slice);
+
time_elapsed = jiffies - tg->slice_start[rw];
nr_slices = time_elapsed / throtl_slice;
struct throtl_grp *tg;
struct hlist_node *pos, *n;
- /*
- * Make sure atomic_inc() effects from
- * throtl_update_blkio_group_read_bps(), group of functions are
- * visible.
- * Is this required or smp_mb__after_atomic_inc() was suffcient
- * after the atomic_inc().
- */
- smp_rmb();
if (!atomic_read(&td->limits_changed))
return;
throtl_log(td, "limit changed =%d", atomic_read(&td->limits_changed));
- hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) {
- /*
- * Do I need an smp_rmb() here to make sure tg->limits_changed
- * update is visible. I am relying on smp_rmb() at the
- * beginning of function and not putting a new one here.
- */
+ /*
+ * Make sure updates from throtl_update_blkio_group_read_bps() group
+ * of functions to tg->limits_changed are visible. We do not
+ * want update td->limits_changed to be visible but update to
+ * tg->limits_changed not being visible yet on this cpu. Hence
+ * the read barrier.
+ */
+ smp_rmb();
+ hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) {
if (throtl_tg_on_rr(tg) && tg->limits_changed) {
throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu"
" riops=%u wiops=%u", tg->bps[READ],
return_ACPI_STATUS(AE_OK);
}
+ /* Disable the GPE in case it's been enabled already. */
+ (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+
/*
* Add the GPE information from above to the gpe_event_info block for
* use during dispatch of this GPE.
unsigned long flags;
};
-static int acpi_battery_update(struct acpi_battery *battery);
-
#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
inline int acpi_battery_present(struct acpi_battery *battery)
int ret = 0;
struct acpi_battery *battery = to_acpi_battery(psy);
- if (acpi_battery_update(battery))
- return -ENODEV;
-
if (acpi_battery_present(battery)) {
/* run battery update only if it is present */
acpi_battery_get_state(battery);
}
static acpi_status
-acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
- union acpi_object *package)
+acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
+ struct acpi_device_wakeup *wakeup)
{
- int i = 0;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *package = NULL;
union acpi_object *element = NULL;
+ acpi_status status;
+ int i = 0;
- if (!device || !package || (package->package.count < 2))
+ if (!wakeup)
return AE_BAD_PARAMETER;
+ /* _PRW */
+ status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
+ return status;
+ }
+
+ package = (union acpi_object *)buffer.pointer;
+
+ if (!package || (package->package.count < 2)) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
+
element = &(package->package.elements[0]);
- if (!element)
- return AE_BAD_PARAMETER;
+ if (!element) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
if (element->type == ACPI_TYPE_PACKAGE) {
if ((element->package.count < 2) ||
(element->package.elements[0].type !=
ACPI_TYPE_LOCAL_REFERENCE)
- || (element->package.elements[1].type != ACPI_TYPE_INTEGER))
- return AE_BAD_DATA;
- device->wakeup.gpe_device =
+ || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
+ wakeup->gpe_device =
element->package.elements[0].reference.handle;
- device->wakeup.gpe_number =
+ wakeup->gpe_number =
(u32) element->package.elements[1].integer.value;
} else if (element->type == ACPI_TYPE_INTEGER) {
- device->wakeup.gpe_number = element->integer.value;
- } else
- return AE_BAD_DATA;
+ wakeup->gpe_device = NULL;
+ wakeup->gpe_number = element->integer.value;
+ } else {
+ status = AE_BAD_DATA;
+ goto out;
+ }
element = &(package->package.elements[1]);
if (element->type != ACPI_TYPE_INTEGER) {
- return AE_BAD_DATA;
+ status = AE_BAD_DATA;
+ goto out;
}
- device->wakeup.sleep_state = element->integer.value;
+ wakeup->sleep_state = element->integer.value;
if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
- return AE_NO_MEMORY;
+ status = AE_NO_MEMORY;
+ goto out;
}
- device->wakeup.resources.count = package->package.count - 2;
- for (i = 0; i < device->wakeup.resources.count; i++) {
+ wakeup->resources.count = package->package.count - 2;
+ for (i = 0; i < wakeup->resources.count; i++) {
element = &(package->package.elements[i + 2]);
- if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
- return AE_BAD_DATA;
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
- device->wakeup.resources.handles[i] = element->reference.handle;
+ wakeup->resources.handles[i] = element->reference.handle;
}
- acpi_gpe_can_wake(device->wakeup.gpe_device, device->wakeup.gpe_number);
+ acpi_gpe_can_wake(wakeup->gpe_device, wakeup->gpe_number);
- return AE_OK;
+ out:
+ kfree(buffer.pointer);
+
+ return status;
}
static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
{
acpi_status status = 0;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *package = NULL;
int psw_error;
- /* _PRW */
- status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
- goto end;
- }
-
- package = (union acpi_object *)buffer.pointer;
- status = acpi_bus_extract_wakeup_device_power_package(device, package);
+ status = acpi_bus_extract_wakeup_device_power_package(device->handle,
+ &device->wakeup);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
goto end;
}
- kfree(buffer.pointer);
-
device->wakeup.flags.valid = 1;
device->wakeup.prepare_count = 0;
acpi_bus_set_run_wake_flags(device);
struct acpi_bus_ops *ops = context;
int type;
unsigned long long sta;
+ struct acpi_device_wakeup wakeup;
struct acpi_device *device;
acpi_status status;
int result;
return AE_OK;
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
- !(sta & ACPI_STA_DEVICE_FUNCTIONING))
+ !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
+ acpi_bus_extract_wakeup_device_power_package(handle, &wakeup);
return AE_CTRL_DEPTH;
+ }
/*
* We may already have an acpi_device from a previous enumeration. If
If unsure, say N.
-config PATA_MPC52xx
- tristate "Freescale MPC52xx SoC internal IDE"
- depends on PPC_MPC52xx && PPC_BESTCOMM
- select PPC_BESTCOMM_ATA
- help
- This option enables support for integrated IDE controller
- of the Freescale MPC52xx SoC.
-
- If unsure, say N.
-
config PATA_OCTEON_CF
tristate "OCTEON Boot Bus Compact Flash support"
depends on CPU_CAVIUM_OCTEON
config PATA_CS5536
tristate "CS5536 PATA support"
- depends on PCI && X86 && !X86_64
+ depends on PCI
help
This option enables support for the AMD CS5536
companion chip used with the Geode LX processor family.
If unsure, say N.
+config PATA_MPC52xx
+ tristate "Freescale MPC52xx SoC internal IDE"
+ depends on PPC_MPC52xx && PPC_BESTCOMM
+ select PPC_BESTCOMM_ATA
+ help
+ This option enables support for integrated IDE controller
+ of the Freescale MPC52xx SoC.
+
+ If unsure, say N.
+
config PATA_NETCELL
tristate "NETCELL Revolution RAID support"
depends on PCI
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
-obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
obj-$(CONFIG_PATA_OCTEON_CF) += pata_octeon_cf.o
obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o
obj-$(CONFIG_SATA_SX4) += sata_sx4.o
obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
obj-$(CONFIG_PATA_MACIO) += pata_macio.o
obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o
+obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
obj-$(CONFIG_PATA_NINJA32) += pata_ninja32.o
obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o
{
struct ata_device *dev = qc->dev;
- if (ata_tag_internal(qc->tag))
- return;
-
if (ata_is_nodata(qc->tf.protocol))
return;
if (unlikely(qc->err_mask))
qc->flags |= ATA_QCFLAG_FAILED;
- if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
- /* always fill result TF for failed qc */
+ /*
+ * Finish internal commands without any further processing
+ * and always with the result TF filled.
+ */
+ if (unlikely(ata_tag_internal(qc->tag))) {
fill_result_tf(qc);
+ __ata_qc_complete(qc);
+ return;
+ }
- if (!ata_tag_internal(qc->tag))
- ata_qc_schedule_eh(qc);
- else
- __ata_qc_complete(qc);
+ /*
+ * Non-internal qc has failed. Fill the result TF and
+ * summon EH.
+ */
+ if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
+ fill_result_tf(qc);
+ ata_qc_schedule_eh(qc);
return;
}
struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL;
struct ata_eh_context *ehc = &link->eh_context;
struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
+ enum ata_lpm_policy old_policy = link->lpm_policy;
unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
unsigned int err_mask;
int rc;
goto fail;
}
+ /*
+ * Low level driver acked the transition. Issue DIPM command
+ * with the new policy set.
+ */
+ link->lpm_policy = policy;
+ if (ap && ap->slave_link)
+ ap->slave_link->lpm_policy = policy;
+
/* host config updated, enable DIPM if transitioning to MIN_POWER */
ata_for_each_dev(dev, link, ENABLED) {
if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) {
}
}
- link->lpm_policy = policy;
- if (ap && ap->slave_link)
- ap->slave_link->lpm_policy = policy;
return 0;
fail:
+ /* restore the old policy */
+ link->lpm_policy = old_policy;
+ if (ap && ap->slave_link)
+ ap->slave_link->lpm_policy = old_policy;
+
/* if no device or only one more chance is left, disable LPM */
if (!dev || ehc->tries[dev->devno] <= 2) {
ata_link_printk(link, KERN_WARNING,
if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
return ata_sff_idle_irq(ap);
break;
- case HSM_ST:
- case HSM_ST_LAST:
- break;
- default:
+ case HSM_ST_IDLE:
return ata_sff_idle_irq(ap);
+ default:
+ break;
}
/* check main status, clearing INTRQ if needed */
#include <linux/delay.h>
#include <linux/libata.h>
#include <scsi/scsi_host.h>
+
+#ifdef CONFIG_X86_32
#include <asm/msr.h>
+static int use_msr;
+module_param_named(msr, use_msr, int, 0644);
+MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
+#else
+#undef rdmsr /* avoid accidental MSR usage on, e.g. x86-64 */
+#undef wrmsr
+#define rdmsr(x, y, z) do { } while (0)
+#define wrmsr(x, y, z) do { } while (0)
+#define use_msr 0
+#endif
#define DRV_NAME "pata_cs5536"
-#define DRV_VERSION "0.0.7"
+#define DRV_VERSION "0.0.8"
enum {
CFG = 0,
IDE_ETC_NODMA = 0x03,
};
-static int use_msr;
-
static const u32 msr_reg[4] = {
MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC,
};
static inline int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
{
if (unlikely(use_msr)) {
- u32 dummy;
+ u32 dummy __maybe_unused;
rdmsr(msr_reg[reg], *val, dummy);
return 0;
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, cs5536);
MODULE_VERSION(DRV_VERSION);
-module_param_named(msr, use_msr, int, 0644);
-MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
module_init(cs5536_init);
module_exit(cs5536_exit);
atm_dev_put(dev);
return -EMEDIUMTYPE;
}
- if (PRIV(dev)->vcc) return -EBUSY;
+ if (PRIV(dev)->vcc) {
+ atm_dev_put(dev);
+ return -EBUSY;
+ }
}
else {
int error;
InquiryData_struct *inq_buff = NULL;
for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
+ if (!h->drv[logvol])
+ continue;
if (memcmp(h->drv[logvol]->LunID, drv->LunID,
sizeof(drv->LunID)) == 0) {
FOUND = 1;
}
shs = drbd_cmd_handler[cmd].pkt_size - sizeof(union p_header);
- rv = drbd_recv(mdev, &header->h80.payload, shs);
- if (unlikely(rv != shs)) {
- dev_err(DEV, "short read while reading sub header: rv=%d\n", rv);
- goto err_out;
- }
-
if (packet_size - shs > 0 && !drbd_cmd_handler[cmd].expect_payload) {
dev_err(DEV, "No payload expected %s l:%d\n", cmdname(cmd), packet_size);
goto err_out;
}
+ if (shs) {
+ rv = drbd_recv(mdev, &header->h80.payload, shs);
+ if (unlikely(rv != shs)) {
+ dev_err(DEV, "short read while reading sub header: rv=%d\n", rv);
+ goto err_out;
+ }
+ }
+
rv = drbd_cmd_handler[cmd].function(mdev, cmd, packet_size - shs);
if (unlikely(!rv)) {
}
/* completion of master bio is outside of spinlock.
- * If you need it irqsave, do it your self! */
+ * If you need it irqsave, do it your self!
+ * Which means: don't use from bio endio callback. */
static inline int req_mod(struct drbd_request *req,
enum drbd_req_event what)
{
*/
void drbd_endio_pri(struct bio *bio, int error)
{
+ unsigned long flags;
struct drbd_request *req = bio->bi_private;
struct drbd_conf *mdev = req->mdev;
+ struct bio_and_error m;
enum drbd_req_event what;
int uptodate = bio_flagged(bio, BIO_UPTODATE);
bio_put(req->private_bio);
req->private_bio = ERR_PTR(error);
- req_mod(req, what);
+ /* not req_mod(), we need irqsave here! */
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ __req_mod(req, what, &m);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ if (m.bio)
+ complete_master_bio(mdev, &m);
}
int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
hu->proto->close(hu);
- hci_unregister_dev(hdev);
- hci_free_dev(hdev);
+ if (hdev) {
+ hci_unregister_dev(hdev);
+ hci_free_dev(hdev);
+ }
}
}
}
writel(1, intel_private.i9xx_flush_page);
}
-static void i965_write_entry(dma_addr_t addr, unsigned int entry,
+static void i965_write_entry(dma_addr_t addr,
+ unsigned int entry,
unsigned int flags)
{
+ u32 pte_flags;
+
+ pte_flags = I810_PTE_VALID;
+ if (flags == AGP_USER_CACHED_MEMORY)
+ pte_flags |= I830_PTE_SYSTEM_CACHED;
+
/* Shift high bits down */
addr |= (addr >> 28) & 0xf0;
- writel(addr | I810_PTE_VALID, intel_private.gtt + entry);
+ writel(addr | pte_flags, intel_private.gtt + entry);
}
static bool gen6_check_flags(unsigned int flags)
#include <linux/ramoops.h>
#define RAMOOPS_KERNMSG_HDR "===="
-#define RAMOOPS_HEADER_SIZE (5 + sizeof(struct timeval))
#define RECORD_SIZE 4096
struct ramoops_context, dump);
unsigned long s1_start, s2_start;
unsigned long l1_cpy, l2_cpy;
- int res;
- char *buf;
+ int res, hdr_size;
+ char *buf, *buf_orig;
struct timeval timestamp;
/* Only dump oopses if dump_oops is set */
return;
buf = (char *)(cxt->virt_addr + (cxt->count * RECORD_SIZE));
+ buf_orig = buf;
+
memset(buf, '\0', RECORD_SIZE);
res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
buf += res;
res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
buf += res;
- l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE));
- l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE) - l2_cpy);
+ hdr_size = buf - buf_orig;
+ l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - hdr_size));
+ l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - hdr_size) - l2_cpy);
s2_start = l2 - l2_cpy;
s1_start = l1 - l1_cpy;
} while (delay);
}
-static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
+static void __sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
{
- unsigned long flags;
-
if (delta > p->max_match_value)
dev_warn(&p->pdev->dev, "delta out of range\n");
- spin_lock_irqsave(&p->lock, flags);
p->next_match_value = delta;
sh_cmt_clock_event_program_verify(p, 0);
+}
+
+static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->lock, flags);
+ __sh_cmt_set_next(p, delta);
spin_unlock_irqrestore(&p->lock, flags);
}
/* setup timeout if no clockevent */
if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT)))
- sh_cmt_set_next(p, p->max_match_value);
+ __sh_cmt_set_next(p, p->max_match_value);
out:
spin_unlock_irqrestore(&p->lock, flags);
/* adjust the timeout to maximum if only clocksource left */
if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE))
- sh_cmt_set_next(p, p->max_match_value);
+ __sh_cmt_set_next(p, p->max_match_value);
spin_unlock_irqrestore(&p->lock, flags);
}
static void mv_xor_tasklet(unsigned long data)
{
struct mv_xor_chan *chan = (struct mv_xor_chan *) data;
- __mv_xor_slot_cleanup(chan);
+ mv_xor_slot_cleanup(chan);
}
static struct mv_xor_desc_slot *
* registers, see include/linux/cs5535.h.
*/
-static void errata_outl(u32 val, unsigned long addr)
+static void errata_outl(struct cs5535_gpio_chip *chip, u32 val,
+ unsigned int reg)
{
+ unsigned long addr = chip->base + 0x80 + reg;
+
/*
* According to the CS5536 errata (#36), after suspend
* a write to the high bank GPIO register will clear all
* non-selected bits; the recommended workaround is a
* read-modify-write operation.
+ *
+ * Don't apply this errata to the edge status GPIOs, as writing
+ * to their lower bits will clear them.
*/
- val |= inl(addr);
+ if (reg != GPIO_POSITIVE_EDGE_STS && reg != GPIO_NEGATIVE_EDGE_STS) {
+ if (val & 0xffff)
+ val |= (inl(addr) & 0xffff); /* ignore the high bits */
+ else
+ val |= (inl(addr) ^ (val >> 16));
+ }
outl(val, addr);
}
outl(1 << offset, chip->base + reg);
else
/* high bank register */
- errata_outl(1 << (offset - 16), chip->base + 0x80 + reg);
+ errata_outl(chip, 1 << (offset - 16), reg);
}
void cs5535_gpio_set(unsigned offset, unsigned int reg)
outl(1 << (offset + 16), chip->base + reg);
else
/* high bank register */
- errata_outl(1 << offset, chip->base + 0x80 + reg);
+ errata_outl(chip, 1 << offset, reg);
}
void cs5535_gpio_clear(unsigned offset, unsigned int reg)
err = gpio_direction_output(gpio,
(flags & GPIOF_INIT_HIGH) ? 1 : 0);
+ if (err)
+ gpio_free(gpio);
+
return err;
}
EXPORT_SYMBOL_GPL(gpio_request_one);
struct rdc321x_gpio *rdc321x_gpio_dev;
struct rdc321x_gpio_pdata *pdata;
- pdata = pdev->dev.platform_data;
+ pdata = platform_get_drvdata(pdev);
if (!pdata) {
dev_err(&pdev->dev, "no platform data supplied\n");
return -ENODEV;
}
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- if (encoder->crtc && !drm_helper_encoder_in_use(encoder)) {
+ if (!drm_helper_encoder_in_use(encoder)) {
drm_encoder_disable(encoder);
/* disconnector encoder from any connector */
encoder->crtc = NULL;
continue;
connector->status = connector->funcs->detect(connector, false);
- DRM_DEBUG_KMS("connector status updated to %d\n", connector->status);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+ connector->base.id,
+ drm_get_connector_name(connector),
+ old_status, connector->status);
if (old_status != connector->status)
changed = true;
}
static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo)
{
- return connector_status_unknown;
+ return connector_status_connected;
}
static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
#include "i915_drm.h"
#include "i915_drv.h"
#include "i915_trace.h"
+#include "../../../platform/x86/intel_ips.h"
#include <linux/pci.h>
#include <linux/vgaarb.h>
#include <linux/acpi.h>
EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
/**
+ * Tells the intel_ips driver that the i915 driver is now loaded, if
+ * IPS got loaded first.
+ *
+ * This awkward dance is so that neither module has to depend on the
+ * other in order for IPS to do the appropriate communication of
+ * GPU turbo limits to i915.
+ */
+static void
+ips_ping_for_i915_load(void)
+{
+ void (*link)(void);
+
+ link = symbol_get(ips_link_to_i915_driver);
+ if (link) {
+ link();
+ symbol_put(ips_link_to_i915_driver);
+ }
+}
+
+/**
* i915_driver_load - setup chip and create an initial config
* @dev: DRM device
* @flags: startup flags
dev_priv->mchdev_lock = &mchdev_lock;
spin_unlock(&mchdev_lock);
+ ips_ping_for_i915_load();
+
return 0;
out_workqueue_free:
# define MARIUNIT_CLOCK_GATE_DISABLE (1 << 18)
# define SVSMUNIT_CLOCK_GATE_DISABLE (1 << 1)
+#define PCH_3DCGDIS1 0x46024
+# define VFMUNIT_CLOCK_GATE_DISABLE (1 << 11)
+
#define FDI_PLL_FREQ_CTL 0x46030
#define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24)
#define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00
#define ILK_DISPLAY_CHICKEN2 0x42004
#define ILK_DPARB_GATE (1<<22)
#define ILK_VSDPFD_FULL (1<<21)
+#define ILK_DISPLAY_CHICKEN_FUSES 0x42014
+#define ILK_INTERNAL_GRAPHICS_DISABLE (1<<31)
+#define ILK_INTERNAL_DISPLAY_DISABLE (1<<30)
+#define ILK_DISPLAY_DEBUG_DISABLE (1<<29)
+#define ILK_HDCP_DISABLE (1<<25)
+#define ILK_eDP_A_DISABLE (1<<24)
+#define ILK_DESKTOP (1<<23)
#define ILK_DSPCLK_GATE 0x42020
#define ILK_DPARB_CLK_GATE (1<<5)
/* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */
return index_mask;
}
+static bool has_edp_a(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!IS_MOBILE(dev))
+ return false;
+
+ if ((I915_READ(DP_A) & DP_DETECTED) == 0)
+ return false;
+
+ if (IS_GEN5(dev) &&
+ (I915_READ(ILK_DISPLAY_CHICKEN_FUSES) & ILK_eDP_A_DISABLE))
+ return false;
+
+ return true;
+}
+
static void intel_setup_outputs(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
if (HAS_PCH_SPLIT(dev)) {
dpd_is_edp = intel_dpd_is_edp(dev);
- if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
+ if (has_edp_a(dev))
intel_dp_init(dev, DP_A);
if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
I915_WRITE(PCH_3DCGDIS0,
MARIUNIT_CLOCK_GATE_DISABLE |
SVSMUNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(PCH_3DCGDIS1,
+ VFMUNIT_CLOCK_GATE_DISABLE);
}
I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
uint16_t address = algo_data->address;
uint8_t msg[5];
uint8_t reply[2];
+ unsigned retry;
int msg_bytes;
int reply_bytes;
int ret;
break;
}
- for (;;) {
- ret = intel_dp_aux_ch(intel_dp,
- msg, msg_bytes,
- reply, reply_bytes);
+ for (retry = 0; retry < 5; retry++) {
+ ret = intel_dp_aux_ch(intel_dp,
+ msg, msg_bytes,
+ reply, reply_bytes);
if (ret < 0) {
DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
return ret;
}
+
+ switch (reply[0] & AUX_NATIVE_REPLY_MASK) {
+ case AUX_NATIVE_REPLY_ACK:
+ /* I2C-over-AUX Reply field is only valid
+ * when paired with AUX ACK.
+ */
+ break;
+ case AUX_NATIVE_REPLY_NACK:
+ DRM_DEBUG_KMS("aux_ch native nack\n");
+ return -EREMOTEIO;
+ case AUX_NATIVE_REPLY_DEFER:
+ udelay(100);
+ continue;
+ default:
+ DRM_ERROR("aux_ch invalid native reply 0x%02x\n",
+ reply[0]);
+ return -EREMOTEIO;
+ }
+
switch (reply[0] & AUX_I2C_REPLY_MASK) {
case AUX_I2C_REPLY_ACK:
if (mode == MODE_I2C_READ) {
}
return reply_bytes - 1;
case AUX_I2C_REPLY_NACK:
- DRM_DEBUG_KMS("aux_ch nack\n");
+ DRM_DEBUG_KMS("aux_i2c nack\n");
return -EREMOTEIO;
case AUX_I2C_REPLY_DEFER:
- DRM_DEBUG_KMS("aux_ch defer\n");
+ DRM_DEBUG_KMS("aux_i2c defer\n");
udelay(100);
break;
default:
- DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]);
+ DRM_ERROR("aux_i2c invalid reply 0x%02x\n", reply[0]);
return -EREMOTEIO;
}
}
+
+ DRM_ERROR("too many retries, giving up\n");
+ return -EREMOTEIO;
}
static int
drm_i915_private_t *dev_priv = dev->dev_private;
u32 head;
- head = intel_read_status_page(ring, 4);
- if (head) {
- ring->head = head & HEAD_ADDR;
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->size;
- if (ring->space >= n)
- return 0;
- }
-
trace_i915_ring_wait_begin (dev);
end = jiffies + 3 * HZ;
do {
- ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+ /* If the reported head position has wrapped or hasn't advanced,
+ * fallback to the slow and accurate path.
+ */
+ head = intel_read_status_page(ring, 4);
+ if (head < ring->actual_head)
+ head = I915_READ_HEAD(ring);
+ ring->actual_head = head;
+ ring->head = head & HEAD_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->size;
struct drm_device *dev;
struct drm_gem_object *gem_object;
- unsigned int head;
- unsigned int tail;
+ u32 actual_head;
+ u32 head;
+ u32 tail;
int space;
struct intel_hw_status_page status_page;
speed = mapping->i2c_speed;
}
- sdvo->i2c = &dev_priv->gmbus[pin].adapter;
- intel_gmbus_set_speed(sdvo->i2c, speed);
- intel_gmbus_force_bit(sdvo->i2c, true);
+ if (pin < GMBUS_NUM_PORTS) {
+ sdvo->i2c = &dev_priv->gmbus[pin].adapter;
+ intel_gmbus_set_speed(sdvo->i2c, speed);
+ intel_gmbus_force_bit(sdvo->i2c, true);
+ } else
+ sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter;
}
static bool
SDVO_COLORIMETRY_RGB256);
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
- intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
intel_sdvo->is_hdmi = true;
}
intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT));
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+ if (intel_sdvo->is_hdmi)
+ intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
return true;
}
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
- atombios_blank_crtc(crtc, ATOM_ENABLE);
+ if (radeon_crtc->enabled)
+ atombios_blank_crtc(crtc, ATOM_ENABLE);
if (ASIC_IS_DCE3(rdev))
atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
atombios_enable_crtc(crtc, ATOM_DISABLE);
dp_clock = dig_connector->dp_clock;
}
}
-
+#if 0 /* doesn't work properly on some laptops */
/* use recommended ref_div for ss */
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
if (ss_enabled) {
}
}
}
-
+#endif
if (ASIC_IS_AVIVO(rdev)) {
/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
unsigned i;
u32 tmp;
+ WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+
WREG32(VM_CONTEXT0_REQUEST_RESPONSE, REQUEST_TYPE(1));
for (i = 0; i < rdev->usec_timeout; i++) {
/* read MC_STATUS */
static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
{
struct evergreen_mc_save save;
- u32 srbm_reset = 0;
u32 grbm_reset = 0;
dev_info(rdev->dev, "GPU softreset \n");
udelay(50);
WREG32(GRBM_SOFT_RESET, 0);
(void)RREG32(GRBM_SOFT_RESET);
-
- /* reset all the system blocks */
- srbm_reset = SRBM_SOFT_RESET_ALL_MASK;
-
- dev_info(rdev->dev, " SRBM_SOFT_RESET=0x%08X\n", srbm_reset);
- WREG32(SRBM_SOFT_RESET, srbm_reset);
- (void)RREG32(SRBM_SOFT_RESET);
- udelay(50);
- WREG32(SRBM_SOFT_RESET, 0);
- (void)RREG32(SRBM_SOFT_RESET);
/* Wait a little for things to settle down */
udelay(50);
dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
RREG32(GRBM_STATUS_SE1));
dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n",
RREG32(SRBM_STATUS));
- /* After reset we need to reinit the asic as GPU often endup in an
- * incoherent state.
- */
- atom_asic_init(rdev->mode_info.atom_context);
evergreen_mc_resume(rdev, &save);
return 0;
}
{
int r;
+ /* reset the asic, the gfx blocks are often in a bad state
+ * after the driver is unloaded or after a resume
+ */
+ if (radeon_asic_reset(rdev))
+ dev_warn(rdev->dev, "GPU reset failed !\n");
/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
* posting will perform necessary task to bring back GPU into good
* shape.
r = radeon_atombios_init(rdev);
if (r)
return r;
+ /* reset the asic, the gfx blocks are often in a bad state
+ * after the driver is unloaded or after a resume
+ */
+ if (radeon_asic_reset(rdev))
+ dev_warn(rdev->dev, "GPU reset failed !\n");
/* Post card if necessary */
if (!evergreen_card_posted(rdev)) {
if (!rdev->bios) {
#define HDP_NONSURFACE_BASE 0x2C04
#define HDP_NONSURFACE_INFO 0x2C08
#define HDP_NONSURFACE_SIZE 0x2C0C
+#define HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480
#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0
#define HDP_TILING_CONFIG 0x2F3C
u32 srbm_status;
u32 grbm_status;
u32 grbm_status2;
+ struct r100_gpu_lockup *lockup;
int r;
+ if (rdev->family >= CHIP_RV770)
+ lockup = &rdev->config.rv770.lockup;
+ else
+ lockup = &rdev->config.r600.lockup;
+
srbm_status = RREG32(R_000E50_SRBM_STATUS);
grbm_status = RREG32(R_008010_GRBM_STATUS);
grbm_status2 = RREG32(R_008014_GRBM_STATUS2);
if (!G_008010_GUI_ACTIVE(grbm_status)) {
- r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp);
+ r100_gpu_lockup_update(lockup, &rdev->cp);
return false;
}
/* force CP activities */
radeon_ring_unlock_commit(rdev);
}
rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
- return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
+ return r100_gpu_cp_is_lockup(rdev, lockup, &rdev->cp);
}
int r600_asic_reset(struct radeon_device *rdev)
if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
/* the initial DDX does bad things with the CB size occasionally */
/* it rounds up height too far for slice tile max but the BO is smaller */
- tmp = (height - 7) * 8 * bpe;
- if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
- dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
- return -EINVAL;
- }
+ /* r600c,g also seem to flush at bad times in some apps resulting in
+ * bogus values here. So for linear just allow anything to avoid breaking
+ * broken userspace.
+ */
} else {
dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
return -EINVAL;
radeon_pm_resume(rdev);
radeon_restore_bios_scratch_regs(rdev);
- /* turn on display hw */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
- }
-
radeon_fbdev_set_suspend(rdev, 0);
release_console_sem();
radeon_hpd_init(rdev);
/* blat the mode back in */
drm_helper_resume_force_mode(dev);
+ /* turn on display hw */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+ }
return 0;
}
static struct drm_driver kms_driver;
+static void radeon_kick_out_firmware_fb(struct pci_dev *pdev)
+{
+ struct apertures_struct *ap;
+ bool primary = false;
+
+ ap = alloc_apertures(1);
+ ap->ranges[0].base = pci_resource_start(pdev, 0);
+ ap->ranges[0].size = pci_resource_len(pdev, 0);
+
+#ifdef CONFIG_X86
+ primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+#endif
+ remove_conflicting_framebuffers(ap, "radeondrmfb", primary);
+ kfree(ap);
+}
+
static int __devinit
radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
+ /* Get rid of things like offb */
+ radeon_kick_out_firmware_fb(pdev);
+
return drm_get_pci_dev(pdev, ent, &kms_driver);
}
goto out_unref;
}
info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base;
- info->apertures->ranges[0].size = rdev->mc.real_vram_size;
+ info->apertures->ranges[0].size = rdev->mc.aper_size;
info->fix.mmio_start = 0;
info->fix.mmio_len = 0;
attr->index = channel;
attr->dev_attr.attr.name = attrs->in_name;
attr->dev_attr.attr.mode = S_IRUGO;
- attr->dev_attr.attr.owner = THIS_MODULE;
attr->dev_attr.show = s3c_hwmon_ch_show;
ret = device_create_file(dev, &attr->dev_attr);
attr->index = channel;
attr->dev_attr.attr.name = attrs->label_name;
attr->dev_attr.attr.mode = S_IRUGO;
- attr->dev_attr.attr.owner = THIS_MODULE;
attr->dev_attr.show = s3c_hwmon_label_show;
ret = device_create_file(dev, &attr->dev_attr);
if (b3skb == NULL) {
dev_err(cs->dev, "%s: out of memory\n", __func__);
send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
+ kfree(b3cmsg);
return;
}
capi_cmsg2message(b3cmsg,
unsigned long *delay_off)
{
if (led_cdev->blink_set &&
- led_cdev->blink_set(led_cdev, delay_on, delay_off))
+ !led_cdev->blink_set(led_cdev, delay_on, delay_off))
return;
/* blink with 1 Hz as default if nothing specified */
*/
if (q->merge_bvec_fn && !ti->type->merge)
- limits->max_sectors =
- min_not_zero(limits->max_sectors,
- (unsigned int) (PAGE_SIZE >> 9));
+ blk_limits_max_hw_sectors(limits,
+ (unsigned int) (PAGE_SIZE >> 9));
return 0;
}
EXPORT_SYMBOL_GPL(dm_set_device_limits);
*/
q->limits = *limits;
- if (limits->no_cluster)
- queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
- else
- queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q);
-
if (!dm_table_supports_discards(t))
queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q);
else
goto abort;
mddev->queue->queuedata = mddev;
- /* Can be unlocked because the queue is new: no concurrency */
- queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, mddev->queue);
-
blk_queue_make_request(mddev->queue, md_make_request);
disk = alloc_disk(1 << shift);
{ 0x800f040a, KEY_DELETE },
{ 0x800f040b, KEY_ENTER },
- { 0x800f040c, KEY_POWER },
- { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
+ { 0x800f040c, KEY_POWER }, /* PC Power */
+ { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
{ 0x800f040e, KEY_MUTE },
{ 0x800f040f, KEY_INFO },
{ 0x800f0422, KEY_OK },
{ 0x800f0423, KEY_EXIT },
{ 0x800f0424, KEY_DVD },
- { 0x800f0425, KEY_TUNER }, /* LiveTV */
- { 0x800f0426, KEY_EPG }, /* Guide */
- { 0x800f0427, KEY_ZOOM }, /* Aspect */
+ { 0x800f0425, KEY_TUNER }, /* LiveTV */
+ { 0x800f0426, KEY_EPG }, /* Guide */
+ { 0x800f0427, KEY_ZOOM }, /* Aspect */
{ 0x800f043a, KEY_BRIGHTNESSUP },
{ 0x800f0446, KEY_TV },
- { 0x800f0447, KEY_AUDIO }, /* My Music */
- { 0x800f0448, KEY_PVR }, /* RecordedTV */
+ { 0x800f0447, KEY_AUDIO }, /* My Music */
+ { 0x800f0448, KEY_PVR }, /* RecordedTV */
{ 0x800f0449, KEY_CAMERA },
{ 0x800f044a, KEY_VIDEO },
{ 0x800f044c, KEY_LANGUAGE },
{ 0x800f044d, KEY_TITLE },
- { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
+ { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
{ 0x800f0450, KEY_RADIO },
- { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
+ { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
{ 0x800f045b, KEY_RED },
{ 0x800f045c, KEY_GREEN },
{ 0x800f045d, KEY_YELLOW },
{ 0x800f045e, KEY_BLUE },
+ { 0x800f0465, KEY_POWER2 }, /* TV Power */
{ 0x800f046e, KEY_PLAYPAUSE },
- { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */
+ { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */
{ 0x800f0480, KEY_BRIGHTNESSDOWN },
{ 0x800f0481, KEY_PLAYPAUSE },
dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
- if (!ir->attached) {
- mutex_unlock(&ir->irctl_lock);
+ if (!ir->attached)
return POLLERR;
- }
poll_wait(file, &ir->buf->wait_poll, wait);
if (!buf)
return -ENOMEM;
- if (mutex_lock_interruptible(&ir->irctl_lock))
- return -ERESTARTSYS;
+ if (mutex_lock_interruptible(&ir->irctl_lock)) {
+ ret = -ERESTARTSYS;
+ goto out_unlocked;
+ }
if (!ir->attached) {
- mutex_unlock(&ir->irctl_lock);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_locked;
}
if (length % ir->chunk_size) {
- dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n",
- ir->d.name, ir->d.minor);
- mutex_unlock(&ir->irctl_lock);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_locked;
}
/*
lirc_buffer_read(ir->buf, buf);
ret = copy_to_user((void *)buffer+written, buf,
ir->buf->chunk_size);
- written += ir->buf->chunk_size;
+ if (!ret)
+ written += ir->buf->chunk_size;
+ else
+ ret = -EFAULT;
}
}
remove_wait_queue(&ir->buf->wait_poll, &wait);
set_current_state(TASK_RUNNING);
+
+out_locked:
mutex_unlock(&ir->irctl_lock);
out_unlocked:
kfree(buf);
dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
- ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret);
+ ir->d.name, ir->d.minor, ret ? "<fail>" : "<ok>", ret);
return ret ? ret : written;
}
#include <linux/device.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
#include <media/ir-core.h>
-#include <media/ir-common.h>
#define DRIVER_VERSION "1.91"
#define DRIVER_AUTHOR "Jarod Wilson <jarod@wilsonet.com>"
#define USB_BUFLEN 32 /* USB reception buffer length */
#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
+#define MS_TO_NS(msec) ((msec) * 1000)
/* MCE constants */
#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */
#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */
/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
+#define MCE_CMD_SIG_END 0x01 /* End of signal */
#define MCE_CMD_PING 0x03 /* Ping device */
#define MCE_CMD_UNKNOWN 0x04 /* Unknown */
#define MCE_CMD_UNKNOWN2 0x05 /* Unknown */
#define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */
#define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */
#define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */
+#define MCE_RSP_PULSE_COUNT 0x15 /* RX pulse count (only if learning) */
#define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */
#define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */
#define MCE_CMD_UNKNOWN7 0x18 /* Unknown */
MCE_GEN3,
MCE_GEN2_TX_INV,
POLARIS_EVK,
+ CX_HYBRID_TV,
};
struct mceusb_model {
u32 mce_gen1:1;
u32 mce_gen2:1;
u32 mce_gen3:1;
- u32 tx_mask_inverted:1;
+ u32 tx_mask_normal:1;
u32 is_polaris:1;
+ u32 no_tx:1;
const char *rc_map; /* Allow specify a per-board map */
const char *name; /* per-board name */
static const struct mceusb_model mceusb_model[] = {
[MCE_GEN1] = {
.mce_gen1 = 1,
- .tx_mask_inverted = 1,
+ .tx_mask_normal = 1,
},
[MCE_GEN2] = {
.mce_gen2 = 1,
},
[MCE_GEN2_TX_INV] = {
.mce_gen2 = 1,
- .tx_mask_inverted = 1,
+ .tx_mask_normal = 1,
},
[MCE_GEN3] = {
.mce_gen3 = 1,
- .tx_mask_inverted = 1,
+ .tx_mask_normal = 1,
},
[POLARIS_EVK] = {
.is_polaris = 1,
* to allow testing it
*/
.rc_map = RC_MAP_RC5_HAUPPAUGE_NEW,
- .name = "cx231xx MCE IR",
+ .name = "Conexant Hybrid TV (cx231xx) MCE IR",
+ },
+ [CX_HYBRID_TV] = {
+ .is_polaris = 1,
+ .no_tx = 1, /* tx isn't wired up at all */
+ .name = "Conexant Hybrid TV (cx231xx) MCE IR",
},
};
{ USB_DEVICE(VENDOR_FORMOSA, 0xe03c) },
/* Formosa Industrial Computing */
{ USB_DEVICE(VENDOR_FORMOSA, 0xe03e) },
+ /* Fintek eHome Infrared Transceiver (HP branded) */
+ { USB_DEVICE(VENDOR_FINTEK, 0x5168) },
/* Fintek eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_FINTEK, 0x0602) },
/* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
{ USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
/* TiVo PC IR Receiver */
{ USB_DEVICE(VENDOR_TIVO, 0x2000) },
- /* Conexant SDK */
+ /* Conexant Hybrid TV "Shelby" Polaris SDK */
{ USB_DEVICE(VENDOR_CONEXANT, 0x58a1),
.driver_info = POLARIS_EVK },
+ /* Conexant Hybrid TV RDU253S Polaris */
+ { USB_DEVICE(VENDOR_CONEXANT, 0x58a5),
+ .driver_info = CX_HYBRID_TV },
/* Terminating entry */
{ }
};
struct mceusb_dev {
/* ir-core bits */
struct ir_dev_props *props;
- struct ir_raw_event rawir;
+
+ /* optional features we can enable */
+ bool carrier_report_enabled;
+ bool learning_enabled;
/* core device bits */
struct device *dev;
/* buffers and dma */
unsigned char *buf_in;
unsigned int len_in;
+ dma_addr_t dma_in;
+ dma_addr_t dma_out;
enum {
CMD_HEADER = 0,
CMD_DATA,
PARSE_IRDATA,
} parser_state;
- u8 cmd, rem; /* Remaining IR data bytes in packet */
- dma_addr_t dma_in;
- dma_addr_t dma_out;
+ u8 cmd, rem; /* Remaining IR data bytes in packet */
struct {
u32 connected:1;
- u32 tx_mask_inverted:1;
+ u32 tx_mask_normal:1;
u32 microsoft_gen1:1;
+ u32 no_tx:1;
} flags;
/* transmit support */
case MCE_CMD_UNKNOWN:
case MCE_CMD_S_CARRIER:
case MCE_CMD_S_TIMEOUT:
- case MCE_CMD_G_RXSENSOR:
+ case MCE_RSP_PULSE_COUNT:
datasize = 2;
break;
+ case MCE_CMD_SIG_END:
case MCE_CMD_S_TXMASK:
case MCE_CMD_S_RXSENSOR:
datasize = 1;
return;
/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
- if (ir->flags.microsoft_gen1 && !out)
+ if (ir->flags.microsoft_gen1 && !out && !offset)
skip = 2;
if (len <= skip)
break;
case MCE_COMMAND_HEADER:
switch (subcmd) {
+ case MCE_CMD_SIG_END:
+ dev_info(dev, "End of signal\n");
+ break;
case MCE_CMD_PING:
dev_info(dev, "Ping\n");
break;
inout, data1 == 0x02 ? "short" : "long");
break;
case MCE_CMD_G_RXSENSOR:
- if (len == 2)
+ /* aka MCE_RSP_PULSE_COUNT */
+ if (out)
dev_info(dev, "Get receive sensor\n");
- else
- dev_info(dev, "Received pulse count is %d\n",
+ else if (ir->learning_enabled)
+ dev_info(dev, "RX pulse count: %d\n",
((data1 << 8) | data2));
break;
case MCE_RSP_CMD_INVALID:
return ret ? ret : n;
}
-/* Sets active IR outputs -- mce devices typically (all?) have two */
+/* Sets active IR outputs -- mce devices typically have two */
static int mceusb_set_tx_mask(void *priv, u32 mask)
{
struct mceusb_dev *ir = priv;
- if (ir->flags.tx_mask_inverted)
+ if (ir->flags.tx_mask_normal)
+ ir->tx_mask = mask;
+ else
ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ?
mask ^ MCE_DEFAULT_TX_MASK : mask) << 1;
- else
- ir->tx_mask = mask;
return 0;
}
if (carrier == 0) {
ir->carrier = carrier;
- cmdbuf[2] = 0x01;
+ cmdbuf[2] = MCE_CMD_SIG_END;
cmdbuf[3] = MCE_IRDATA_TRAILER;
dev_dbg(ir->dev, "%s: disabling carrier "
"modulation\n", __func__);
return carrier;
}
+/*
+ * We don't do anything but print debug spew for many of the command bits
+ * we receive from the hardware, but some of them are useful information
+ * we want to store so that we can use them.
+ */
+static void mceusb_handle_command(struct mceusb_dev *ir, int index)
+{
+ u8 hi = ir->buf_in[index + 1] & 0xff;
+ u8 lo = ir->buf_in[index + 2] & 0xff;
+
+ switch (ir->buf_in[index]) {
+ /* 2-byte return value commands */
+ case MCE_CMD_S_TIMEOUT:
+ ir->props->timeout = MS_TO_NS((hi << 8 | lo) / 2);
+ break;
+
+ /* 1-byte return value commands */
+ case MCE_CMD_S_TXMASK:
+ ir->tx_mask = hi;
+ break;
+ case MCE_CMD_S_RXSENSOR:
+ ir->learning_enabled = (hi == 0x02);
+ break;
+ default:
+ break;
+ }
+}
+
static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
{
DEFINE_IR_RAW_EVENT(rawir);
if (ir->flags.microsoft_gen1)
i = 2;
+ /* if there's no data, just return now */
+ if (buf_len <= i)
+ return;
+
for (; i < buf_len; i++) {
switch (ir->parser_state) {
case SUBCMD:
ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]);
mceusb_dev_printdata(ir, ir->buf_in, i - 1,
ir->rem + 2, false);
+ mceusb_handle_command(ir, i);
ir->parser_state = CMD_DATA;
break;
case PARSE_IRDATA:
ir->rem--;
rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
- * MCE_TIME_UNIT * 1000;
-
- if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) {
- if (ir->rawir.pulse == rawir.pulse) {
- ir->rawir.duration += rawir.duration;
- } else {
- ir->rawir.duration = rawir.duration;
- ir->rawir.pulse = rawir.pulse;
- }
- if (ir->rem)
- break;
- }
- rawir.duration += ir->rawir.duration;
- ir->rawir.duration = 0;
- ir->rawir.pulse = rawir.pulse;
+ * MS_TO_NS(MCE_TIME_UNIT);
dev_dbg(ir->dev, "Storing %s with duration %d\n",
rawir.pulse ? "pulse" : "space",
rawir.duration);
- ir_raw_event_store(ir->idev, &rawir);
+ ir_raw_event_store_with_filter(ir->idev, &rawir);
break;
case CMD_DATA:
ir->rem--;
continue;
}
ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
- mceusb_dev_printdata(ir, ir->buf_in, i, ir->rem + 1, false);
- if (ir->rem) {
+ mceusb_dev_printdata(ir, ir->buf_in,
+ i, ir->rem + 1, false);
+ if (ir->rem)
ir->parser_state = PARSE_IRDATA;
- break;
- }
- /*
- * a package with len=0 (e. g. 0x80) means end of
- * data. We could use it to do the call to
- * ir_raw_event_handle(). For now, we don't need to
- * use it.
- */
break;
}
mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
mce_sync_in(ir, NULL, maxp);
- /* get the transmitter bitmask */
- mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
- mce_sync_in(ir, NULL, maxp);
+ if (!ir->flags.no_tx) {
+ /* get the transmitter bitmask */
+ mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
+ mce_sync_in(ir, NULL, maxp);
+ }
/* get receiver timeout value */
mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT));
props->priv = ir;
props->driver_type = RC_DRIVER_IR_RAW;
props->allowed_protos = IR_TYPE_ALL;
- props->s_tx_mask = mceusb_set_tx_mask;
- props->s_tx_carrier = mceusb_set_tx_carrier;
- props->tx_ir = mceusb_tx_ir;
+ props->timeout = MS_TO_NS(1000);
+ if (!ir->flags.no_tx) {
+ props->s_tx_mask = mceusb_set_tx_mask;
+ props->s_tx_carrier = mceusb_set_tx_carrier;
+ props->tx_ir = mceusb_tx_ir;
+ }
ir->props = props;
+ usb_to_input_id(ir->usbdev, &idev->id);
+ idev->dev.parent = ir->dev;
+
if (mceusb_model[ir->model].rc_map)
rc_map = mceusb_model[ir->model].rc_map;
enum mceusb_model_type model = id->driver_info;
bool is_gen3;
bool is_microsoft_gen1;
- bool tx_mask_inverted;
+ bool tx_mask_normal;
bool is_polaris;
- dev_dbg(&intf->dev, ": %s called\n", __func__);
+ dev_dbg(&intf->dev, "%s called\n", __func__);
idesc = intf->cur_altsetting;
is_gen3 = mceusb_model[model].mce_gen3;
is_microsoft_gen1 = mceusb_model[model].mce_gen1;
- tx_mask_inverted = mceusb_model[model].tx_mask_inverted;
+ tx_mask_normal = mceusb_model[model].tx_mask_normal;
is_polaris = mceusb_model[model].is_polaris;
if (is_polaris) {
ep_in = ep;
ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
ep_in->bInterval = 1;
- dev_dbg(&intf->dev, ": acceptable inbound endpoint "
+ dev_dbg(&intf->dev, "acceptable inbound endpoint "
"found\n");
}
ep_out = ep;
ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
ep_out->bInterval = 1;
- dev_dbg(&intf->dev, ": acceptable outbound endpoint "
+ dev_dbg(&intf->dev, "acceptable outbound endpoint "
"found\n");
}
}
if (ep_in == NULL) {
- dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n");
+ dev_dbg(&intf->dev, "inbound and/or endpoint not found\n");
return -ENODEV;
}
ir->dev = &intf->dev;
ir->len_in = maxp;
ir->flags.microsoft_gen1 = is_microsoft_gen1;
- ir->flags.tx_mask_inverted = tx_mask_inverted;
+ ir->flags.tx_mask_normal = tx_mask_normal;
+ ir->flags.no_tx = mceusb_model[model].no_tx;
ir->model = model;
- init_ir_raw_event(&ir->rawir);
-
/* Saving usb interface data for use by the transmitter routine */
ir->usb_ep_in = ep_in;
ir->usb_ep_out = ep_out;
mceusb_get_parameters(ir);
- mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK);
+ if (!ir->flags.no_tx)
+ mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK);
usb_set_intfdata(intf, ir);
count = nvt->pkts;
nvt_dbg_verbose("Processing buffer of len %d", count);
+ init_ir_raw_event(&rawir);
+
for (i = 0; i < count; i++) {
nvt->pkts--;
sample = nvt->buf[i];
* indicates end of IR signal, but new data incoming. In both
* cases, it means we're ready to call ir_raw_event_handle
*/
- if (sample == BUF_PULSE_BIT || ((sample != BUF_LEN_MASK) &&
- (sample & BUF_REPEAT_MASK) == BUF_REPEAT_BYTE))
+ if ((sample == BUF_PULSE_BIT) && nvt->pkts) {
+ nvt_dbg("Calling ir_raw_event_handle (signal end)\n");
ir_raw_event_handle(nvt->rdev);
+ }
}
+ nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n");
+ ir_raw_event_handle(nvt->rdev);
+
if (nvt->pkts) {
nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts);
nvt->pkts = 0;
#include <linux/device.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
#include <media/ir-core.h>
#define DRIVER_VERSION "1.61"
static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
{
- ir_raw_event_store(sz->idev, &rawir);
+ dev_dbg(sz->dev, "Storing %s with duration %u us\n",
+ (rawir.pulse ? "pulse" : "space"), rawir.duration);
+ ir_raw_event_store_with_filter(sz->idev, &rawir);
}
static void sz_push_full_pulse(struct streamzap_ir *sz,
rawir.duration *= 1000;
rawir.duration &= IR_MAX_DURATION;
}
- dev_dbg(sz->dev, "ls %u\n", rawir.duration);
sz_push(sz, rawir);
sz->idle = false;
sz->sum += rawir.duration;
rawir.duration *= 1000;
rawir.duration &= IR_MAX_DURATION;
- dev_dbg(sz->dev, "p %u\n", rawir.duration);
sz_push(sz, rawir);
}
rawir.duration += SZ_RESOLUTION / 2;
sz->sum += rawir.duration;
rawir.duration *= 1000;
- dev_dbg(sz->dev, "s %u\n", rawir.duration);
sz_push(sz, rawir);
}
struct streamzap_ir *sz;
unsigned int i;
int len;
- static int timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
- IR_MAX_DURATION) | 0x03000000);
if (!urb)
return;
dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len);
for (i = 0; i < len; i++) {
- dev_dbg(sz->dev, "sz idx %d: %x\n",
+ dev_dbg(sz->dev, "sz->buf_in[%d]: %x\n",
i, (unsigned char)sz->buf_in[i]);
switch (sz->decoder_state) {
case PulseSpace:
DEFINE_IR_RAW_EVENT(rawir);
rawir.pulse = false;
- rawir.duration = timeout;
+ rawir.duration = sz->props->timeout;
sz->idle = true;
if (sz->timeout_enabled)
sz_push(sz, rawir);
sz->props = props;
+ usb_to_input_id(sz->usbdev, &idev->id);
+ idev->dev.parent = sz->dev;
+
ret = ir_input_register(idev, RC_MAP_STREAMZAP, props, DRIVER_NAME);
if (ret < 0) {
dev_err(dev, "remote input device register failed\n");
sz->decoder_state = PulseSpace;
/* FIXME: don't yet have a way to set this */
sz->timeout_enabled = true;
+ sz->props->timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
+ IR_MAX_DURATION) | 0x03000000);
#if 0
/* not yet supported, depends on patches from maxim */
/* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
{
struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_format *sfmt = format_by_fourcc(dev, pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat);
int b_depth = vv->ov_fmt->depth;
int b_bpl = vv->ov_fb.fmt.bytesperline;
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_video_dma vdma1;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
int width = buf->fmt->width;
int height = buf->fmt->height;
struct saa7146_video_dma vdma2;
struct saa7146_video_dma vdma3;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
int width = buf->fmt->width;
int height = buf->fmt->height;
void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
{
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
struct saa7146_vv *vv = dev->vv_data;
u32 vdma1_prot_addr;
static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format);
-struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc)
+struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc)
{
int i, j = NUM_FORMATS;
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
struct scatterlist *list = dma->sglist;
int length = dma->sglen;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
}
}
- fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
/* we need to have a valid format set here */
BUG_ON(NULL == fmt);
return -EBUSY;
}
- fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
/* we need to have a valid format set here */
BUG_ON(NULL == fmt);
return -EPERM;
/* check args */
- fmt = format_by_fourcc(dev, fb->fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat);
if (NULL == fmt)
return -EINVAL;
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
- fmt = format_by_fourcc(dev, f->fmt.pix.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
buf->fmt = &fh->video_fmt;
buf->vb.field = fh->video_fmt.field;
- sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
release_all_pagetables(dev, buf);
if( 0 != IS_PLANAR(sfmt->trans)) {
fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24;
fh->video_fmt.bytesperline = 0;
fh->video_fmt.field = V4L2_FIELD_ANY;
- sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ sfmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8;
videobuf_queue_sg_init(&fh->video_q, &video_qops,
static const struct v4l2_file_operations rtrack_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
rt->vdev.release = video_device_release_empty;
video_set_drvdata(&rt->vdev, rt);
- if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(&rt->v4l2_dev);
- release_region(rt->io, 2);
- return -EINVAL;
- }
- v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
-
/* Set up the I/O locking */
mutex_init(&rt->lock);
sleep_delay(2000000); /* make sure it's totally down */
outb(0xc0, rt->io); /* steady volume, mute card */
+ if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(&rt->v4l2_dev);
+ release_region(rt->io, 2);
+ return -EINVAL;
+ }
+ v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
+
return 0;
}
static const struct v4l2_file_operations aztech_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
az->vdev.ioctl_ops = &aztech_ioctl_ops;
az->vdev.release = video_device_release_empty;
video_set_drvdata(&az->vdev, az);
+ /* mute card - prevents noisy bootups */
+ outb(0, az->io);
if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
}
v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
- /* mute card - prevents noisy bootups */
- outb(0, az->io);
return 0;
}
unsigned char readbuf[RDS_BUFFER];
int i = 0;
+ mutex_lock(&dev->lock);
if (dev->rdsstat == 0) {
- mutex_lock(&dev->lock);
dev->rdsstat = 1;
outb(0x80, dev->io); /* Select RDS fifo */
- mutex_unlock(&dev->lock);
init_timer(&dev->readtimer);
dev->readtimer.function = cadet_handler;
dev->readtimer.data = (unsigned long)dev;
add_timer(&dev->readtimer);
}
if (dev->rdsin == dev->rdsout) {
+ mutex_unlock(&dev->lock);
if (file->f_flags & O_NONBLOCK)
return -EWOULDBLOCK;
interruptible_sleep_on(&dev->read_queue);
+ mutex_lock(&dev->lock);
}
while (i < count && dev->rdsin != dev->rdsout)
readbuf[i++] = dev->rdsbuf[dev->rdsout++];
+ mutex_unlock(&dev->lock);
if (copy_to_user(data, readbuf, i))
return -EFAULT;
{
struct cadet *dev = video_drvdata(file);
+ mutex_lock(&dev->lock);
dev->users++;
if (1 == dev->users)
init_waitqueue_head(&dev->read_queue);
+ mutex_unlock(&dev->lock);
return 0;
}
{
struct cadet *dev = video_drvdata(file);
+ mutex_lock(&dev->lock);
dev->users--;
if (0 == dev->users) {
del_timer_sync(&dev->readtimer);
dev->rdsstat = 0;
}
+ mutex_unlock(&dev->lock);
return 0;
}
.open = cadet_open,
.release = cadet_release,
.read = cadet_read,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = cadet_poll,
};
static const struct v4l2_file_operations gemtek_pci_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = {
card->vdev.release = video_device_release_empty;
video_set_drvdata(&card->vdev, card);
+ gemtek_pci_mute(card);
+
if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0)
goto err_video;
- gemtek_pci_mute(card);
-
v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
pdev->revision, card->iobase, card->iobase + card->length - 1);
static const struct v4l2_file_operations gemtek_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static int vidioc_querycap(struct file *file, void *priv,
gt->vdev.release = video_device_release_empty;
video_set_drvdata(>->vdev, gt);
- if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(gt->io, 1);
- return -EBUSY;
- }
-
/* Set defaults */
gt->lastfreq = GEMTEK_LOWFREQ;
gt->bu2614data = 0;
if (initmute)
gemtek_mute(gt);
+ if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(v4l2_dev);
+ release_region(gt->io, 1);
+ return -EBUSY;
+ }
+
return 0;
}
static const struct v4l2_file_operations maestro_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
+ if (!radio_power_on(dev)) {
+ retval = -EIO;
+ goto errfr1;
+ }
+
retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
if (retval) {
v4l2_err(v4l2_dev, "can't register video device!\n");
goto errfr1;
}
- if (!radio_power_on(dev)) {
- retval = -EIO;
- goto errunr;
- }
-
v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
return 0;
-errunr:
- video_unregister_device(&dev->vdev);
errfr1:
v4l2_device_unregister(v4l2_dev);
errfr:
static const struct v4l2_file_operations maxiradio_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
unsigned long freq;
int muted;
struct snd_miro_aci *aci;
+ struct mutex lock;
};
static struct pcm20 pcm20_card = {
static const struct v4l2_file_operations pcm20_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static int vidioc_querycap(struct file *file, void *priv,
return -ENODEV;
}
strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name));
-
+ mutex_init(&dev->lock);
res = v4l2_device_register(NULL, v4l2_dev);
if (res < 0) {
dev->vdev.fops = &pcm20_fops;
dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
dev->vdev.release = video_device_release_empty;
+ dev->vdev.lock = &dev->lock;
video_set_drvdata(&dev->vdev, dev);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
static const struct v4l2_file_operations rtrack2_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
+ /* mute card - prevents noisy bootups */
+ outb(1, dev->io);
+ dev->muted = 1;
+
mutex_init(&dev->lock);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
- /* mute card - prevents noisy bootups */
- outb(1, dev->io);
- dev->muted = 1;
-
return 0;
}
static const struct v4l2_file_operations fmi_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
mutex_init(&fmi->lock);
+ /* mute card - prevents noisy bootups */
+ fmi_mute(fmi);
+
if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(fmi->io, 2);
}
v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io);
- /* mute card - prevents noisy bootups */
- fmi_mute(fmi);
return 0;
}
static const struct v4l2_file_operations fmr2_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops fmr2_ioctl_ops = {
fmr2->vdev.release = video_device_release_empty;
video_set_drvdata(&fmr2->vdev, fmr2);
+ /* mute card - prevents noisy bootups */
+ fmr2_mute(fmr2->io);
+ fmr2_product_info(fmr2);
+
if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(fmr2->io, 2);
}
v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io);
- /* mute card - prevents noisy bootups */
- mutex_lock(&fmr2->lock);
- fmr2_mute(fmr2->io);
- fmr2_product_info(fmr2);
- mutex_unlock(&fmr2->lock);
debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type));
return 0;
}
/* radio_si4713_fops - file operations interface */
static const struct v4l2_file_operations radio_si4713_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ /* Note: locking is done at the subdev level in the i2c driver. */
+ .unlocked_ioctl = video_ioctl2,
};
/* Video4Linux Interface */
struct video_device *videodev;
struct tea5764_regs regs;
struct mutex mutex;
- int users;
};
/* I2C code related */
return 0;
}
-static int tea5764_open(struct file *file)
-{
- /* Currently we support only one device */
- struct tea5764_device *radio = video_drvdata(file);
-
- mutex_lock(&radio->mutex);
- /* Only exclusive access */
- if (radio->users) {
- mutex_unlock(&radio->mutex);
- return -EBUSY;
- }
- radio->users++;
- mutex_unlock(&radio->mutex);
- file->private_data = radio;
- return 0;
-}
-
-static int tea5764_close(struct file *file)
-{
- struct tea5764_device *radio = video_drvdata(file);
-
- if (!radio)
- return -ENODEV;
- mutex_lock(&radio->mutex);
- radio->users--;
- mutex_unlock(&radio->mutex);
- return 0;
-}
-
/* File system interface */
static const struct v4l2_file_operations tea5764_fops = {
.owner = THIS_MODULE,
- .open = tea5764_open,
- .release = tea5764_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
int ret;
PDEBUG("probe");
- radio = kmalloc(sizeof(struct tea5764_device), GFP_KERNEL);
+ radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL);
if (!radio)
return -ENOMEM;
i2c_set_clientdata(client, radio);
video_set_drvdata(radio->videodev, radio);
-
- ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
- if (ret < 0) {
- PWARN("Could not register video device!");
- goto errrel;
- }
+ radio->videodev->lock = &radio->mutex;
/* initialize and power off the chip */
tea5764_i2c_read(radio);
tea5764_mute(radio, 1);
tea5764_power_down(radio);
+ ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (ret < 0) {
+ PWARN("Could not register video device!");
+ goto errrel;
+ }
+
PINFO("registered.");
return 0;
errrel:
static const struct v4l2_file_operations terratec_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
mutex_init(&tt->lock);
+ /* mute card - prevents noisy bootups */
+ tt_write_vol(tt, 0);
+
if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(&tt->v4l2_dev);
release_region(tt->io, 2);
}
v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
-
- /* mute card - prevents noisy bootups */
- tt_write_vol(tt, 0);
return 0;
}
struct v4l2_subdev *sd_dsp;
struct video_device video_dev;
struct v4l2_device v4l2_dev;
+ struct mutex lock;
};
static const struct v4l2_file_operations timbradio_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static int __devinit timbradio_probe(struct platform_device *pdev)
}
tr->pdata = *pdata;
+ mutex_init(&tr->lock);
strlcpy(tr->video_dev.name, "Timberdale Radio",
sizeof(tr->video_dev.name));
tr->video_dev.ioctl_ops = &timbradio_ioctl_ops;
tr->video_dev.release = video_device_release_empty;
tr->video_dev.minor = -1;
+ tr->video_dev.lock = &tr->lock;
strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
err = v4l2_device_register(NULL, &tr->v4l2_dev);
static const struct v4l2_file_operations trust_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops trust_ioctl_ops = {
tr->vdev.release = video_device_release_empty;
video_set_drvdata(&tr->vdev, tr);
- if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(tr->io, 2);
- return -EINVAL;
- }
-
- v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
-
write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
/* mute card - prevents noisy bootups */
tr_setmute(tr, 1);
+ if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(v4l2_dev);
+ release_region(tr->io, 2);
+ return -EINVAL;
+ }
+
+ v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
+
return 0;
}
static const struct v4l2_file_operations typhoon_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name));
dev->io = io;
- dev->curfreq = dev->mutefreq = mutefreq;
if (dev->io == -1) {
v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n");
return -EINVAL;
}
- if (dev->mutefreq < 87000 || dev->mutefreq > 108500) {
+ if (mutefreq < 87000 || mutefreq > 108500) {
v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n");
v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
return -EINVAL;
}
+ dev->curfreq = dev->mutefreq = mutefreq << 4;
mutex_init(&dev->lock);
if (!request_region(dev->io, 8, "typhoon")) {
dev->vdev.ioctl_ops = &typhoon_ioctl_ops;
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
+
+ /* mute card - prevents noisy bootups */
+ typhoon_mute(dev);
+
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(&dev->v4l2_dev);
release_region(dev->io, 8);
return -EINVAL;
}
v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io);
- v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", dev->mutefreq);
- dev->mutefreq <<= 4;
-
- /* mute card - prevents noisy bootups */
- typhoon_mute(dev);
+ v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq);
return 0;
}
static const struct v4l2_file_operations zoltrix_fops =
{
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
return res;
}
- strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
- zol->vdev.v4l2_dev = v4l2_dev;
- zol->vdev.fops = &zoltrix_fops;
- zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
- zol->vdev.release = video_device_release_empty;
- video_set_drvdata(&zol->vdev, zol);
-
- if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(zol->io, 2);
- return -EINVAL;
- }
- v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
-
mutex_init(&zol->lock);
/* mute card - prevents noisy bootups */
zol->curvol = 0;
zol->stereo = 1;
+ strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
+ zol->vdev.v4l2_dev = v4l2_dev;
+ zol->vdev.fops = &zoltrix_fops;
+ zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
+ zol->vdev.release = video_device_release_empty;
+ video_set_drvdata(&zol->vdev, zol);
+
+ if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(v4l2_dev);
+ release_region(zol->io, 2);
+ return -EINVAL;
+ }
+ v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
+
return 0;
}
static const struct v4l2_file_operations ar_fops = {
.owner = THIS_MODULE,
.read = ar_read,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops ar_ioctl_ops = {
xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
/* is it free? */
- mutex_lock(&btv->lock);
if (btv->resources & xbits) {
/* no, someone else uses it */
goto fail;
/* it's free, grab it */
fh->resources |= bit;
btv->resources |= bit;
- mutex_unlock(&btv->lock);
return 1;
fail:
- mutex_unlock(&btv->lock);
return 0;
}
/* trying to free ressources not allocated by us ... */
printk("bttv: BUG! (btres)\n");
}
- mutex_lock(&btv->lock);
fh->resources &= ~bits;
btv->resources &= ~bits;
if (0 == (bits & VBI_RESOURCES))
disclaim_vbi_lines(btv);
-
- mutex_unlock(&btv->lock);
}
/* ----------------------------------------------------------------------- */
/* Make sure tvnorm and vbi_end remain consistent
until we're done. */
- mutex_lock(&btv->lock);
norm = btv->tvnorm;
/* In this mode capturing always starts at defrect.top
(default VDELAY), ignoring cropping parameters. */
if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
- mutex_unlock(&btv->lock);
return -EINVAL;
}
- mutex_unlock(&btv->lock);
-
c.rect = bttv_tvnorms[norm].cropcap.defrect;
} else {
- mutex_lock(&btv->lock);
-
norm = btv->tvnorm;
c = btv->crop[!!fh->do_crop];
- mutex_unlock(&btv->lock);
-
if (width < c.min_scaled_width ||
width > c.max_scaled_width ||
height < c.min_scaled_height)
unsigned int i;
int err;
- mutex_lock(&btv->lock);
err = v4l2_prio_check(&btv->prio, fh->prio);
if (err)
goto err;
set_tvnorm(btv, i);
err:
- mutex_unlock(&btv->lock);
return err;
}
struct bttv *btv = fh->btv;
int rc = 0;
- mutex_lock(&btv->lock);
if (i->index >= bttv_tvcards[btv->c.type].video_inputs) {
rc = -EINVAL;
goto err;
i->std = BTTV_NORMS;
err:
- mutex_unlock(&btv->lock);
return rc;
}
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- mutex_lock(&btv->lock);
*i = btv->input;
- mutex_unlock(&btv->lock);
return 0;
}
int err;
- mutex_lock(&btv->lock);
err = v4l2_prio_check(&btv->prio, fh->prio);
if (unlikely(err))
goto err;
set_input(btv, i, btv->tvnorm);
err:
- mutex_unlock(&btv->lock);
return 0;
}
if (unlikely(0 != t->index))
return -EINVAL;
- mutex_lock(&btv->lock);
if (unlikely(btv->tuner_type == TUNER_ABSENT)) {
err = -EINVAL;
goto err;
btv->audio_mode_gpio(btv, t, 1);
err:
- mutex_unlock(&btv->lock);
return 0;
}
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- mutex_lock(&btv->lock);
f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
f->frequency = btv->freq;
- mutex_unlock(&btv->lock);
return 0;
}
if (unlikely(f->tuner != 0))
return -EINVAL;
- mutex_lock(&btv->lock);
err = v4l2_prio_check(&btv->prio, fh->prio);
if (unlikely(err))
goto err;
if (btv->has_matchbox && btv->radio_user)
tea5757_set_freq(btv, btv->freq);
err:
- mutex_unlock(&btv->lock);
return 0;
}
/* Make sure tvnorm, vbi_end and the current cropping parameters
remain consistent until we're done. */
- mutex_lock(&btv->lock);
b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
rc = 0; /* success */
fail:
- mutex_unlock(&btv->lock);
return rc;
}
if (V4L2_FIELD_ANY == field) {
__s32 height2;
- mutex_lock(&fh->btv->lock);
height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
- mutex_unlock(&fh->btv->lock);
field = (win->w.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
}
}
- mutex_lock(&fh->cap.vb_lock);
/* clip against screen */
if (NULL != btv->fbuf.base)
n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
fh->ov.field = win->field;
fh->ov.setup_ok = 1;
- /*
- * FIXME: btv is protected by btv->lock mutex, while btv->init
- * is protected by fh->cap.vb_lock. This seems to open the
- * possibility for some race situations. Maybe the better would
- * be to unify those locks or to use another way to store the
- * init values that will be consumed by videobuf callbacks
- */
btv->init.ov.w.width = win->w.width;
btv->init.ov.w.height = win->w.height;
btv->init.ov.field = win->field;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
}
- mutex_unlock(&fh->cap.vb_lock);
return retval;
}
if (V4L2_FIELD_ANY == field) {
__s32 height2;
- mutex_lock(&btv->lock);
height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
- mutex_unlock(&btv->lock);
field = (f->fmt.pix.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
/* update our state informations */
- mutex_lock(&fh->cap.vb_lock);
fh->fmt = fmt;
fh->cap.field = f->fmt.pix.field;
fh->cap.last = V4L2_FIELD_NONE;
btv->init.fmt = fmt;
btv->init.width = f->fmt.pix.width;
btv->init.height = f->fmt.pix.height;
- mutex_unlock(&fh->cap.vb_lock);
return 0;
}
unsigned int i;
struct bttv_fh *fh = priv;
- mutex_lock(&fh->cap.vb_lock);
retval = __videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
V4L2_MEMORY_MMAP);
if (retval < 0) {
- mutex_unlock(&fh->cap.vb_lock);
return retval;
}
for (i = 0; i < gbuffers; i++)
mbuf->offsets[i] = i * gbufsize;
- mutex_unlock(&fh->cap.vb_lock);
return 0;
}
#endif
int retval = 0;
if (on) {
- mutex_lock(&fh->cap.vb_lock);
/* verify args */
if (unlikely(!btv->fbuf.base)) {
- mutex_unlock(&fh->cap.vb_lock);
return -EINVAL;
}
if (unlikely(!fh->ov.setup_ok)) {
}
if (retval)
return retval;
- mutex_unlock(&fh->cap.vb_lock);
}
if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY))
return -EBUSY;
- mutex_lock(&fh->cap.vb_lock);
if (on) {
fh->ov.tvnorm = btv->tvnorm;
new = videobuf_sg_alloc(sizeof(*new));
/* switch over */
retval = bttv_switch_overlay(btv, fh, new);
- mutex_unlock(&fh->cap.vb_lock);
return retval;
}
}
/* ok, accept it */
- mutex_lock(&fh->cap.vb_lock);
btv->fbuf.base = fb->base;
btv->fbuf.fmt.width = fb->fmt.width;
btv->fbuf.fmt.height = fb->fmt.height;
retval = bttv_switch_overlay(btv, fh, new);
}
}
- mutex_unlock(&fh->cap.vb_lock);
return retval;
}
c->id >= V4L2_CID_PRIVATE_LASTP1))
return -EINVAL;
- mutex_lock(&btv->lock);
if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
*c = no_ctl;
else {
*c = (NULL != ctrl) ? *ctrl : no_ctl;
}
- mutex_unlock(&btv->lock);
return 0;
}
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
- mutex_lock(&btv->lock);
v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
&parm->parm.capture.timeperframe);
- mutex_unlock(&btv->lock);
return 0;
}
if (0 != t->index)
return -EINVAL;
- mutex_lock(&btv->lock);
t->rxsubchans = V4L2_TUNER_SUB_MONO;
bttv_call_all(btv, tuner, g_tuner, t);
strcpy(t->name, "Television");
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 0);
- mutex_unlock(&btv->lock);
return 0;
}
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
- mutex_lock(&btv->lock);
*p = v4l2_prio_max(&btv->prio);
- mutex_unlock(&btv->lock);
return 0;
}
struct bttv *btv = fh->btv;
int rc;
- mutex_lock(&btv->lock);
rc = v4l2_prio_change(&btv->prio, &fh->prio, prio);
- mutex_unlock(&btv->lock);
return rc;
}
cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
return -EINVAL;
- mutex_lock(&btv->lock);
*cap = bttv_tvnorms[btv->tvnorm].cropcap;
- mutex_unlock(&btv->lock);
return 0;
}
inconsistent with fh->width or fh->height and apps
do not expect a change here. */
- mutex_lock(&btv->lock);
crop->c = btv->crop[!!fh->do_crop].rect;
- mutex_unlock(&btv->lock);
return 0;
}
/* Make sure tvnorm, vbi_end and the current cropping
parameters remain consistent until we're done. Note
read() may change vbi_end in check_alloc_btres_lock(). */
- mutex_lock(&btv->lock);
retval = v4l2_prio_check(&btv->prio, fh->prio);
if (0 != retval) {
- mutex_unlock(&btv->lock);
return retval;
}
retval = -EBUSY;
if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
- mutex_unlock(&btv->lock);
return retval;
}
b_top = max(b->top, btv->vbi_end);
if (b_top + 32 >= b_bottom) {
- mutex_unlock(&btv->lock);
return retval;
}
btv->crop[1] = c;
- mutex_unlock(&btv->lock);
-
fh->do_crop = 1;
- mutex_lock(&fh->cap.vb_lock);
-
if (fh->width < c.min_scaled_width) {
fh->width = c.min_scaled_width;
btv->init.width = c.min_scaled_width;
btv->init.height = c.max_scaled_height;
}
- mutex_unlock(&fh->cap.vb_lock);
-
return 0;
}
return videobuf_poll_stream(file, &fh->vbi, wait);
}
- mutex_lock(&fh->cap.vb_lock);
if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
/* streaming capture */
if (list_empty(&fh->cap.stream))
else
rc = 0;
err:
- mutex_unlock(&fh->cap.vb_lock);
return rc;
}
return -ENOMEM;
file->private_data = fh;
- /*
- * btv is protected by btv->lock mutex, while btv->init and other
- * streaming vars are protected by fh->cap.vb_lock. We need to take
- * care of both locks to avoid troubles. However, vb_lock is used also
- * inside videobuf, without calling buf->lock. So, it is a very bad
- * idea to hold both locks at the same time.
- * Let's first copy btv->init at fh, holding cap.vb_lock, and then work
- * with the rest of init, holding btv->lock.
- */
- mutex_lock(&fh->cap.vb_lock);
*fh = btv->init;
- mutex_unlock(&fh->cap.vb_lock);
fh->type = type;
fh->ov.setup_ok = 0;
- mutex_lock(&btv->lock);
v4l2_prio_open(&btv->prio, &fh->prio);
videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct bttv_buffer),
- fh, NULL);
+ fh, &btv->lock);
videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops,
&btv->c.pci->dev, &btv->s_lock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct bttv_buffer),
- fh, NULL);
+ fh, &btv->lock);
set_tvnorm(btv,btv->tvnorm);
set_input(btv, btv->input, btv->tvnorm);
bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
bttv_field_count(btv);
- mutex_unlock(&btv->lock);
return 0;
}
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
- mutex_lock(&btv->lock);
/* turn off overlay */
if (check_btres(fh, RESOURCE_OVERLAY))
bttv_switch_overlay(btv,fh,NULL);
/* free stuff */
- /*
- * videobuf uses cap.vb_lock - we should avoid holding btv->lock,
- * otherwise we may have dead lock conditions
- */
- mutex_unlock(&btv->lock);
videobuf_mmap_free(&fh->cap);
videobuf_mmap_free(&fh->vbi);
- mutex_lock(&btv->lock);
v4l2_prio_close(&btv->prio, fh->prio);
file->private_data = NULL;
kfree(fh);
if (!btv->users)
audio_mute(btv, 1);
- mutex_unlock(&btv->lock);
return 0;
}
if (unlikely(!fh))
return -ENOMEM;
file->private_data = fh;
- mutex_lock(&fh->cap.vb_lock);
*fh = btv->init;
- mutex_unlock(&fh->cap.vb_lock);
- mutex_lock(&btv->lock);
v4l2_prio_open(&btv->prio, &fh->prio);
btv->radio_user++;
bttv_call_all(btv, tuner, s_radio);
audio_input(btv,TVAUDIO_INPUT_RADIO);
- mutex_unlock(&btv->lock);
return 0;
}
struct bttv *btv = fh->btv;
struct rds_command cmd;
- mutex_lock(&btv->lock);
v4l2_prio_close(&btv->prio, fh->prio);
file->private_data = NULL;
kfree(fh);
btv->radio_user--;
bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd);
- mutex_unlock(&btv->lock);
return 0;
}
return -EINVAL;
if (0 != t->index)
return -EINVAL;
- mutex_lock(&btv->lock);
strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO;
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 0);
- mutex_unlock(&btv->lock);
-
return 0;
}
.open = radio_open,
.read = radio_read,
.release = radio_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = radio_poll,
};
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = qcam_read,
};
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = qcam_read,
};
.read = cafe_v4l_read,
.poll = cafe_v4l_poll,
.mmap = cafe_v4l_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
- return snd_pcm_lib_ioctl(substream, cmd, arg);
+ struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+ int ret;
+
+ snd_cx18_lock(cxsc);
+ ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+ snd_cx18_unlock(cxsc);
+ return ret;
}
.read = cx18_v4l2_read,
.open = cx18_v4l2_open,
/* FIXME change to video_ioctl2 if serialization lock can be removed */
- .ioctl = cx18_v4l2_ioctl,
+ .unlocked_ioctl = cx18_v4l2_ioctl,
.release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll,
};
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
V4L2_CID_HUE, -128, 127, 1, 0);
if (!is_cx2583x(state)) {
- default_volume = 228 - cx25840_read(client, 0x8d4);
- default_volume = ((default_volume / 2) + 23) << 9;
+ default_volume = cx25840_read(client, 0x8d4);
+ /*
+ * Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume
+ * scale mapping limits to avoid -ERANGE errors when
+ * initializing the volume control
+ */
+ if (default_volume > 228) {
+ /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
+ default_volume = 228;
+ cx25840_write(client, 0x8d4, 228);
+ }
+ else if (default_volume < 20) {
+ /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
+ default_volume = 20;
+ cx25840_write(client, 0x8d4, 20);
+ }
+ default_volume = (((228 - default_volume) >> 1) + 23) << 9;
state->volume = v4l2_ctrl_new_std(&state->hdl,
&cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
#include <sound/control.h>
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <media/wm8775.h>
#include "cx88.h"
#include "cx88-reg.h"
int left, right, v, b;
int changed = 0;
u32 old;
- struct v4l2_control client_ctl;
-
- /* Pass volume & balance onto any WM8775 */
- if (value->value.integer.value[0] >= value->value.integer.value[1]) {
- v = value->value.integer.value[0] << 10;
- b = value->value.integer.value[0] ?
- (0x8000 * value->value.integer.value[1]) / value->value.integer.value[0] :
- 0x8000;
- } else {
- v = value->value.integer.value[1] << 10;
- b = value->value.integer.value[1] ?
- 0xffff - (0x8000 * value->value.integer.value[0]) / value->value.integer.value[1] :
- 0x8000;
- }
- client_ctl.value = v;
- client_ctl.id = V4L2_CID_AUDIO_VOLUME;
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
-
- client_ctl.value = b;
- client_ctl.id = V4L2_CID_AUDIO_BALANCE;
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
left = value->value.integer.value[0] & 0x3f;
right = value->value.integer.value[1] & 0x3f;
b = right - left;
if (b < 0) {
- v = 0x3f - left;
- b = (-b) | 0x40;
+ v = 0x3f - left;
+ b = (-b) | 0x40;
} else {
- v = 0x3f - right;
+ v = 0x3f - right;
}
/* Do we really know this will always be called with IRQs on? */
spin_lock_irq(&chip->reg_lock);
old = cx_read(AUD_VOL_CTL);
if (v != (old & 0x3f)) {
- cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
- changed = 1;
+ cx_write(AUD_VOL_CTL, (old & ~0x3f) | v);
+ changed = 1;
}
- if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
- cx_write(AUD_BAL_CTL, b);
- changed = 1;
+ if (cx_read(AUD_BAL_CTL) != b) {
+ cx_write(AUD_BAL_CTL, b);
+ changed = 1;
}
spin_unlock_irq(&chip->reg_lock);
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .name = "Analog-TV Volume",
+ .name = "Playback Volume",
.info = snd_cx88_volume_info,
.get = snd_cx88_volume_get,
.put = snd_cx88_volume_put,
vol = cx_read(AUD_VOL_CTL);
if (value->value.integer.value[0] != !(vol & bit)) {
vol ^= bit;
- cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
- /* Pass mute onto any WM8775 */
- if ((1<<6) == bit) {
- struct v4l2_control client_ctl;
- client_ctl.value = 0 != (vol & bit);
- client_ctl.id = V4L2_CID_AUDIO_MUTE;
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
- }
+ cx_write(AUD_VOL_CTL, vol);
ret = 1;
}
spin_unlock_irq(&chip->reg_lock);
static const struct snd_kcontrol_new snd_cx88_dac_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Audio-Out Switch",
+ .name = "Playback Switch",
.info = snd_ctl_boolean_mono_info,
.get = snd_cx88_switch_get,
.put = snd_cx88_switch_put,
static const struct snd_kcontrol_new snd_cx88_source_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog-TV Switch",
+ .name = "Capture Switch",
.info = snd_ctl_boolean_mono_info,
.get = snd_cx88_switch_get,
.put = snd_cx88_switch_put,
.private_value = (1<<6),
};
-static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core = chip->core;
- struct v4l2_control client_ctl;
-
- client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
- call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl);
- value->value.integer.value[0] = client_ctl.value ? 1 : 0;
-
- return 0;
-}
-
-static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
-{
- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
- struct cx88_core *core = chip->core;
- struct v4l2_control client_ctl;
-
- client_ctl.value = 0 != value->value.integer.value[0];
- client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
-
- return 0;
-}
-
-static struct snd_kcontrol_new snd_cx88_alc_switch = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Line-In ALC Switch",
- .info = snd_ctl_boolean_mono_info,
- .get = snd_cx88_alc_get,
- .put = snd_cx88_alc_put,
-};
-
/****************************************************************************
Basic Flow for Sound Devices
****************************************************************************/
{
struct snd_card *card;
snd_cx88_card_t *chip;
- struct v4l2_subdev *sd;
int err;
if (devno >= SNDRV_CARDS)
if (err < 0)
goto error;
- /* If there's a wm8775 then add a Line-In ALC switch */
- list_for_each_entry(sd, &chip->core->v4l2_dev.subdevs, list) {
- if (WM8775_GID == sd->grp_id) {
- snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch,
- chip));
- break;
- }
- }
-
strcpy (card->driver, "CX88x");
sprintf(card->shortname, "Conexant CX%x", pci->device);
sprintf(card->longname, "%s at %#llx",
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .audio_chip = V4L2_IDENT_WM8775,
.input = {{
.type = CX88_VMUX_DVB,
.vmux = 0,
+ /* 2: Line-In */
+ .audioroute = 2,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
+ /* 2: Line-In */
+ .audioroute = 2,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
+ /* 2: Line-In */
+ .audioroute = 2,
}},
.mpeg = CX88_MPEG_DVB,
},
#include "cx88.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/wm8775.h>
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
const struct cx88_ctrl *c = NULL;
u32 value,mask;
int i;
- struct v4l2_control client_ctl;
for (i = 0; i < CX8800_CTLS; i++) {
if (cx8800_ctls[i].v.id == ctl->id) {
ctl->value = c->v.minimum;
if (ctl->value > c->v.maximum)
ctl->value = c->v.maximum;
-
- /* Pass changes onto any WM8775 */
- client_ctl.id = ctl->id;
- switch (ctl->id) {
- case V4L2_CID_AUDIO_MUTE:
- client_ctl.value = ctl->value;
- break;
- case V4L2_CID_AUDIO_VOLUME:
- client_ctl.value = (ctl->value) ?
- (0x90 + ctl->value) << 8 : 0;
- break;
- case V4L2_CID_AUDIO_BALANCE:
- client_ctl.value = ctl->value << 9;
- break;
- default:
- client_ctl.id = 0;
- break;
- }
- if (client_ctl.id)
- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
-
mask=c->mask;
switch (ctl->id) {
case V4L2_CID_AUDIO_BALANCE:
if (c->id < V4L2_CID_BASE ||
c->id >= V4L2_CID_LASTP1)
return -EINVAL;
- if (c->id == V4L2_CID_AUDIO_MUTE ||
- c->id == V4L2_CID_AUDIO_VOLUME ||
- c->id == V4L2_CID_AUDIO_BALANCE) {
+ if (c->id == V4L2_CID_AUDIO_MUTE) {
for (i = 0; i < CX8800_CTLS; i++) {
if (cx8800_ctls[i].v.id == c->id)
break;
return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
}
-#define call_hw(core, grpid, o, f, args...) \
+#define call_all(core, o, f, args...) \
do { \
if (!core->i2c_rc) { \
if (core->gate_ctrl) \
core->gate_ctrl(core, 1); \
- v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
+ v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \
if (core->gate_ctrl) \
core->gate_ctrl(core, 0); \
} \
} while (0)
-#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
-
struct cx8800_dev;
struct cx8802_dev;
.owner = THIS_MODULE,
.open = em28xx_v4l2_open,
.release = em28xx_v4l2_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
.owner = THIS_MODULE,
.open = et61x251_open,
.release = et61x251_release,
- .ioctl = et61x251_ioctl,
+ .unlocked_ioctl = et61x251_ioctl,
.read = et61x251_read,
.poll = et61x251_poll,
.mmap = et61x251_mmap,
#define QUALITY_DEF 80
u8 jpegqual; /* webcam quality */
+ u8 reg01;
+ u8 reg17;
u8 reg18;
+ u8 flags;
s8 ag_cnt;
#define AG_CNT_START 13
SENSOR_SP80708,
};
+/* device flags */
+#define PDN_INV 1 /* inverse pin S_PWR_DN / sn_xxx tables */
+
+/* sn9c1xx definitions */
+/* register 0x01 */
+#define S_PWR_DN 0x01 /* sensor power down */
+#define S_PDN_INV 0x02 /* inverse pin S_PWR_DN */
+#define V_TX_EN 0x04 /* video transfer enable */
+#define LED 0x08 /* output to pin LED */
+#define SCL_SEL_OD 0x20 /* open-drain mode */
+#define SYS_SEL_48M 0x40 /* system clock 0: 24MHz, 1: 48MHz */
+/* register 0x17 */
+#define MCK_SIZE_MASK 0x1f /* sensor master clock */
+#define SEN_CLK_EN 0x20 /* enable sensor clock */
+#define DEF_EN 0x80 /* defect pixel by 0: soft, 1: hard */
+
/* V4L2 controls supported by the driver */
static void setbrightness(struct gspca_dev *gspca_dev);
static void setcontrast(struct gspca_dev *gspca_dev);
}
}
-static void bridge_init(struct gspca_dev *gspca_dev,
- const u8 *sn9c1xx)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 reg0102[2];
- const u8 *reg9a;
- static const u8 reg9a_def[] =
- {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
- static const u8 reg9a_spec[] =
- {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
- static const u8 regd4[] = {0x60, 0x00, 0x00};
-
- /* sensor clock already enabled in sd_init */
- /* reg_w1(gspca_dev, 0xf1, 0x00); */
- reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
-
- /* configure gpio */
- reg0102[0] = sn9c1xx[1];
- reg0102[1] = sn9c1xx[2];
- if (gspca_dev->audio)
- reg0102[1] |= 0x04; /* keep the audio connection */
- reg_w(gspca_dev, 0x01, reg0102, 2);
- reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
- reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
- switch (sd->sensor) {
- case SENSOR_GC0307:
- case SENSOR_OV7660:
- case SENSOR_PO1030:
- case SENSOR_PO2030N:
- case SENSOR_SOI768:
- case SENSOR_SP80708:
- reg9a = reg9a_spec;
- break;
- default:
- reg9a = reg9a_def;
- break;
- }
- reg_w(gspca_dev, 0x9a, reg9a, 6);
-
- reg_w(gspca_dev, 0xd4, regd4, sizeof regd4);
-
- reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
-
- switch (sd->sensor) {
- case SENSOR_ADCM1700:
- reg_w1(gspca_dev, 0x01, 0x43);
- reg_w1(gspca_dev, 0x17, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- reg_w1(gspca_dev, 0x01, 0x42);
- break;
- case SENSOR_GC0307:
- msleep(50);
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x22);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- msleep(50);
- break;
- case SENSOR_MI0360B:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x60);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_MT9V111:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x61);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_OM6802:
- msleep(10);
- reg_w1(gspca_dev, 0x02, 0x73);
- reg_w1(gspca_dev, 0x17, 0x60);
- reg_w1(gspca_dev, 0x01, 0x22);
- msleep(100);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x17, 0x64);
- reg_w1(gspca_dev, 0x17, 0x64);
- reg_w1(gspca_dev, 0x01, 0x42);
- msleep(10);
- reg_w1(gspca_dev, 0x01, 0x42);
- i2c_w8(gspca_dev, om6802_init0[0]);
- i2c_w8(gspca_dev, om6802_init0[1]);
- msleep(15);
- reg_w1(gspca_dev, 0x02, 0x71);
- msleep(150);
- break;
- case SENSOR_OV7630:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0xe2);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_OV7648:
- reg_w1(gspca_dev, 0x01, 0x63);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- break;
- case SENSOR_PO1030:
- case SENSOR_SOI768:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_PO2030N:
- case SENSOR_OV7660:
- reg_w1(gspca_dev, 0x01, 0x63);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- break;
- case SENSOR_SP80708:
- reg_w1(gspca_dev, 0x01, 0x63);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- msleep(100);
- reg_w1(gspca_dev, 0x02, 0x62);
- break;
- default:
-/* case SENSOR_HV7131R: */
-/* case SENSOR_MI0360: */
-/* case SENSOR_MO4000: */
- reg_w1(gspca_dev, 0x01, 0x43);
- reg_w1(gspca_dev, 0x17, 0x61);
- reg_w1(gspca_dev, 0x01, 0x42);
- if (sd->sensor == SENSOR_HV7131R)
- hv7131r_probe(gspca_dev);
- break;
- }
-}
-
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
struct cam *cam;
sd->bridge = id->driver_info >> 16;
- sd->sensor = id->driver_info;
+ sd->sensor = id->driver_info >> 8;
+ sd->flags = id->driver_info;
cam = &gspca_dev->cam;
if (sd->sensor == SENSOR_ADCM1700) {
/* setup a selector by bridge */
reg_w1(gspca_dev, 0xf1, 0x01);
reg_r(gspca_dev, 0x00, 1);
- reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]);
+ reg_w1(gspca_dev, 0xf1, 0x00);
reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */
regF1 = gspca_dev->usb_buf[0];
if (gspca_dev->usb_err < 0)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- u8 reg1, reg17;
+ u8 reg01, reg17;
+ u8 reg0102[2];
const u8 *sn9c1xx;
const u8 (*init)[8];
+ const u8 *reg9a;
int mode;
+ static const u8 reg9a_def[] =
+ {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
+ static const u8 reg9a_spec[] =
+ {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
+ static const u8 regd4[] = {0x60, 0x00, 0x00};
static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
static const u8 CA_adcm1700[] =
/* initialize the bridge */
sn9c1xx = sn_tb[sd->sensor];
- bridge_init(gspca_dev, sn9c1xx);
+
+ /* sensor clock already enabled in sd_init */
+ /* reg_w1(gspca_dev, 0xf1, 0x00); */
+ reg01 = sn9c1xx[1];
+ if (sd->flags & PDN_INV)
+ reg01 ^= S_PDN_INV; /* power down inverted */
+ reg_w1(gspca_dev, 0x01, reg01);
+
+ /* configure gpio */
+ reg0102[0] = reg01;
+ reg0102[1] = sn9c1xx[2];
+ if (gspca_dev->audio)
+ reg0102[1] |= 0x04; /* keep the audio connection */
+ reg_w(gspca_dev, 0x01, reg0102, 2);
+ reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
+ reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
+ switch (sd->sensor) {
+ case SENSOR_GC0307:
+ case SENSOR_OV7660:
+ case SENSOR_PO1030:
+ case SENSOR_PO2030N:
+ case SENSOR_SOI768:
+ case SENSOR_SP80708:
+ reg9a = reg9a_spec;
+ break;
+ default:
+ reg9a = reg9a_def;
+ break;
+ }
+ reg_w(gspca_dev, 0x9a, reg9a, 6);
+
+ reg_w(gspca_dev, 0xd4, regd4, sizeof regd4);
+
+ reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
+
+ reg17 = sn9c1xx[0x17];
+ switch (sd->sensor) {
+ case SENSOR_GC0307:
+ msleep(50); /*fixme: is it useful? */
+ break;
+ case SENSOR_OM6802:
+ msleep(10);
+ reg_w1(gspca_dev, 0x02, 0x73);
+ reg17 |= SEN_CLK_EN;
+ reg_w1(gspca_dev, 0x17, reg17);
+ reg_w1(gspca_dev, 0x01, 0x22);
+ msleep(100);
+ reg01 = SCL_SEL_OD | S_PDN_INV;
+ reg17 &= MCK_SIZE_MASK;
+ reg17 |= 0x04; /* clock / 4 */
+ break;
+ }
+ reg01 |= SYS_SEL_48M;
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg17 |= SEN_CLK_EN;
+ reg_w1(gspca_dev, 0x17, reg17);
+ reg01 &= ~S_PWR_DN; /* sensor power on */
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 &= ~SYS_SEL_48M;
+ reg_w1(gspca_dev, 0x01, reg01);
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ hv7131r_probe(gspca_dev); /*fixme: is it useful? */
+ break;
+ case SENSOR_OM6802:
+ msleep(10);
+ reg_w1(gspca_dev, 0x01, reg01);
+ i2c_w8(gspca_dev, om6802_init0[0]);
+ i2c_w8(gspca_dev, om6802_init0[1]);
+ msleep(15);
+ reg_w1(gspca_dev, 0x02, 0x71);
+ msleep(150);
+ break;
+ case SENSOR_SP80708:
+ msleep(100);
+ reg_w1(gspca_dev, 0x02, 0x62);
+ break;
+ }
/* initialize the sensor */
i2c_w_seq(gspca_dev, sensor_init[sd->sensor]);
}
reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
switch (sd->sensor) {
- case SENSOR_GC0307:
- reg17 = 0xa2;
- break;
- case SENSOR_MT9V111:
- case SENSOR_MI0360B:
- reg17 = 0xe0;
- break;
- case SENSOR_ADCM1700:
- case SENSOR_OV7630:
- reg17 = 0xe2;
- break;
- case SENSOR_OV7648:
- reg17 = 0x20;
- break;
- case SENSOR_OV7660:
- case SENSOR_SOI768:
- reg17 = 0xa0;
- break;
- case SENSOR_PO1030:
- case SENSOR_PO2030N:
- reg17 = 0xa0;
+ case SENSOR_OM6802:
+/* case SENSOR_OV7648: * fixme: sometimes */
break;
default:
- reg17 = 0x60;
+ reg17 |= DEF_EN;
break;
}
reg_w1(gspca_dev, 0x17, reg17);
init = NULL;
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
- if (mode)
- reg1 = 0x46; /* 320x240: clk 48Mhz, video trf enable */
- else
- reg1 = 0x06; /* 640x480: clk 24Mhz, video trf enable */
- reg17 = 0x61; /* 0x:20: enable sensor clock */
+ reg01 |= SYS_SEL_48M | V_TX_EN;
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x02; /* clock / 2 */
switch (sd->sensor) {
case SENSOR_ADCM1700:
init = adcm1700_sensor_param1;
- reg1 = 0x46;
- reg17 = 0xe2;
break;
case SENSOR_GC0307:
init = gc0307_sensor_param1;
- reg17 = 0xa2;
- reg1 = 0x44;
+ break;
+ case SENSOR_HV7131R:
+ case SENSOR_MI0360:
+ if (mode)
+ reg01 |= SYS_SEL_48M; /* 320x240: clk 48Mhz */
+ else
+ reg01 &= ~SYS_SEL_48M; /* 640x480: clk 24Mhz */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x01; /* clock / 1 */
break;
case SENSOR_MI0360B:
init = mi0360b_sensor_param1;
- reg1 &= ~0x02; /* don't inverse pin S_PWR_DN */
- reg17 = 0xe2;
break;
case SENSOR_MO4000:
- if (mode) {
-/* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */
- reg1 = 0x06; /* clk 24Mz */
- } else {
- reg17 = 0x22; /* 640 MCKSIZE */
-/* reg1 = 0x06; * 640 clk 24Mz (done) */
+ if (mode) { /* if 320x240 */
+ reg01 &= ~SYS_SEL_48M; /* clk 24Mz */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x01; /* clock / 1 */
}
break;
case SENSOR_MT9V111:
init = mt9v111_sensor_param1;
- if (mode) {
- reg1 = 0x04; /* 320 clk 48Mhz */
- } else {
-/* reg1 = 0x06; * 640 clk 24Mz (done) */
- reg17 = 0xc2;
- }
break;
case SENSOR_OM6802:
init = om6802_sensor_param1;
- reg17 = 0x64; /* 640 MCKSIZE */
+ if (!mode) { /* if 640x480 */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x01; /* clock / 4 */
+ }
break;
case SENSOR_OV7630:
init = ov7630_sensor_param1;
- reg17 = 0xe2;
- reg1 = 0x44;
break;
case SENSOR_OV7648:
init = ov7648_sensor_param1;
- reg17 = 0x21;
-/* reg1 = 0x42; * 42 - 46? */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x01; /* clock / 1 */
break;
case SENSOR_OV7660:
init = ov7660_sensor_param1;
- if (sd->bridge == BRIDGE_SN9C120) {
- if (mode) { /* 320x240 - 160x120 */
- reg17 = 0xa2;
- reg1 = 0x44; /* 48 Mhz, video trf eneble */
- }
- } else {
- reg17 = 0x22;
- reg1 = 0x06; /* 24 Mhz, video trf eneble
- * inverse power down */
- }
break;
case SENSOR_PO1030:
init = po1030_sensor_param1;
- reg17 = 0xa2;
- reg1 = 0x44;
break;
case SENSOR_PO2030N:
init = po2030n_sensor_param1;
- reg1 = 0x46;
- reg17 = 0xa2;
break;
case SENSOR_SOI768:
init = soi768_sensor_param1;
- reg1 = 0x44;
- reg17 = 0xa2;
break;
case SENSOR_SP80708:
init = sp80708_sensor_param1;
- if (mode) {
-/*?? reg1 = 0x04; * 320 clk 48Mhz */
- } else {
- reg1 = 0x46; /* 640 clk 48Mz */
- reg17 = 0xa2;
- }
break;
}
setjpegqual(gspca_dev);
reg_w1(gspca_dev, 0x17, reg17);
- reg_w1(gspca_dev, 0x01, reg1);
+ reg_w1(gspca_dev, 0x01, reg01);
+ sd->reg01 = reg01;
+ sd->reg17 = reg17;
sethvflip(gspca_dev);
setbrightness(gspca_dev);
{ 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 };
static const u8 stopsoi768[] =
{ 0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10 };
- u8 data;
- const u8 *sn9c1xx;
+ u8 reg01;
+ u8 reg17;
- data = 0x0b;
+ reg01 = sd->reg01;
+ reg17 = sd->reg17 & ~SEN_CLK_EN;
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
case SENSOR_GC0307:
- data = 0x29;
+ case SENSOR_PO2030N:
+ case SENSOR_SP80708:
+ reg01 |= LED;
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 &= ~(LED | V_TX_EN);
+ reg_w1(gspca_dev, 0x01, reg01);
+/* reg_w1(gspca_dev, 0x02, 0x??); * LED off ? */
break;
case SENSOR_HV7131R:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
i2c_w8(gspca_dev, stophv7131);
- data = 0x2b;
break;
case SENSOR_MI0360:
case SENSOR_MI0360B:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
+/* reg_w1(gspca_dev, 0x02, 0x40); * LED off ? */
i2c_w8(gspca_dev, stopmi0360);
- data = 0x29;
break;
- case SENSOR_OV7648:
- i2c_w8(gspca_dev, stopov7648);
- /* fall thru */
case SENSOR_MT9V111:
- case SENSOR_OV7630:
+ case SENSOR_OM6802:
case SENSOR_PO1030:
- data = 0x29;
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
+ break;
+ case SENSOR_OV7630:
+ case SENSOR_OV7648:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
+ i2c_w8(gspca_dev, stopov7648);
+ break;
+ case SENSOR_OV7660:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
break;
case SENSOR_SOI768:
i2c_w8(gspca_dev, stopsoi768);
- data = 0x29;
break;
}
- sn9c1xx = sn_tb[sd->sensor];
- reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
- reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
- reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
- reg_w1(gspca_dev, 0x01, data);
+
+ reg01 |= SCL_SEL_OD;
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 |= S_PWR_DN; /* sensor power down */
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg_w1(gspca_dev, 0x17, reg17);
+ reg01 &= ~SYS_SEL_48M; /* clock 24MHz */
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 |= LED;
+ reg_w1(gspca_dev, 0x01, reg01);
/* Don't disable sensor clock as that disables the button on the cam */
/* reg_w1(gspca_dev, 0xf1, 0x01); */
}
/* -- module initialisation -- */
#define BS(bridge, sensor) \
.driver_info = (BRIDGE_ ## bridge << 16) \
- | SENSOR_ ## sensor
+ | (SENSOR_ ## sensor << 8)
+#define BSF(bridge, sensor, flags) \
+ .driver_info = (BRIDGE_ ## bridge << 16) \
+ | (SENSOR_ ## sensor << 8) \
+ | (flags)
static const __devinitdata struct usb_device_id device_table[] = {
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)},
{USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)},
#endif
- {USB_DEVICE(0x045e, 0x00f5), BS(SN9C105, OV7660)},
- {USB_DEVICE(0x045e, 0x00f7), BS(SN9C105, OV7660)},
+ {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, PDN_INV)},
+ {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, PDN_INV)},
{USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)},
{USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)},
{USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)},
.open = meye_open,
.release = meye_release,
.mmap = meye_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = meye_poll,
};
msleep(1);
mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);
- if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
- video_nr) < 0) {
- v4l2_err(v4l2_dev, "video_register_device failed\n");
- goto outvideoreg;
- }
-
mutex_init(&meye.lock);
init_waitqueue_head(&meye.proc_list);
meye.brightness = 32 << 10;
sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
+ if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
+ video_nr) < 0) {
+ v4l2_err(v4l2_dev, "video_register_device failed\n");
+ goto outvideoreg;
+ }
+
v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n",
MEYE_DRIVER_VERSION);
v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n",
if (common_flags & SOCAM_PCLK_SAMPLE_RISING)
csicr1 |= CSICR1_REDGE;
- if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
- csicr1 |= CSICR1_INV_PCLK;
if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH)
csicr1 |= CSICR1_SOF_POL;
if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH)
static const struct v4l2_file_operations pms_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = pms_read,
};
INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
fimc->vid_cap.active_buf_cnt = 0;
fimc->vid_cap.frame_count = 0;
+ fimc->vid_cap.buf_index = fimc_hw_get_frame_index(fimc);
set_bit(ST_CAPT_PEND, &fimc->state);
ret = videobuf_streamon(&fimc->vid_cap.vbq);
return ret;
}
+static int fimc_cap_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
+{
+ struct fimc_frame *f;
+ struct fimc_ctx *ctx = fh;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ f = &ctx->s_frame;
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = f->o_width;
+ cr->bounds.height = f->o_height;
+ cr->defrect = cr->bounds;
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct fimc_frame *f;
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ f = &ctx->s_frame;
+ cr->c.left = f->offs_h;
+ cr->c.top = f->offs_v;
+ cr->c.width = f->width;
+ cr->c.height = f->height;
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
static int fimc_cap_s_crop(struct file *file, void *fh,
struct v4l2_crop *cr)
{
.vidioc_g_ctrl = fimc_vidioc_g_ctrl,
.vidioc_s_ctrl = fimc_cap_s_ctrl,
- .vidioc_g_crop = fimc_vidioc_g_crop,
+ .vidioc_g_crop = fimc_cap_g_crop,
.vidioc_s_crop = fimc_cap_s_crop,
- .vidioc_cropcap = fimc_vidioc_cropcap,
+ .vidioc_cropcap = fimc_cap_cropcap,
.vidioc_enum_input = fimc_cap_enum_input,
.vidioc_s_input = fimc_cap_s_input,
videobuf_queue_dma_contig_init(&vid_cap->vbq, &fimc_qops,
vid_cap->v4l2_dev.dev, &fimc->irqlock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct fimc_vid_buffer), (void *)ctx);
+ sizeof(struct fimc_vid_buffer), (void *)ctx, NULL);
ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret) {
.planes_cnt = 1,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "XRGB-8-8-8-8, 24 bpp",
- .fourcc = V4L2_PIX_FMT_RGB24,
+ .name = "XRGB-8-8-8-8, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_RGB32,
.depth = 32,
.color = S5P_FIMC_RGB888,
.buff_cnt = 1,
{
struct fimc_ctx *ctx = priv;
struct v4l2_queryctrl *c;
+ int ret = -EINVAL;
c = get_ctrl(qc->id);
if (c) {
return 0;
}
- if (ctx->state & FIMC_CTX_CAP)
- return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
+ if (ctx->state & FIMC_CTX_CAP) {
+ if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+ return -ERESTARTSYS;
+ ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
core, queryctrl, qc);
- return -EINVAL;
+ mutex_unlock(&ctx->fimc_dev->lock);
+ }
+ return ret;
}
int fimc_vidioc_g_ctrl(struct file *file, void *priv,
return 0;
}
-int fimc_vidioc_cropcap(struct file *file, void *fh,
+static int fimc_m2m_cropcap(struct file *file, void *fh,
struct v4l2_cropcap *cr)
{
struct fimc_frame *frame;
return 0;
}
-int fimc_vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
{
struct fimc_frame *frame;
struct fimc_ctx *ctx = file->private_data;
struct fimc_frame *f;
u32 min_size, halign;
- f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
- &ctx->s_frame : &ctx->d_frame;
-
if (cr->c.top < 0 || cr->c.left < 0) {
v4l2_err(&fimc->m2m.v4l2_dev,
"doesn't support negative values for top & left\n");
return -EINVAL;
}
- f = ctx_get_frame(ctx, cr->type);
- if (IS_ERR(f))
- return PTR_ERR(f);
+ if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ f = (ctx->state & FIMC_CTX_CAP) ? &ctx->s_frame : &ctx->d_frame;
+ else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ ctx->state & FIMC_CTX_M2M)
+ f = &ctx->s_frame;
+ else
+ return -EINVAL;
- min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- ? fimc->variant->min_inp_pixsize
- : fimc->variant->min_out_pixsize;
+ min_size = (f == &ctx->s_frame) ?
+ fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
if (ctx->state & FIMC_CTX_M2M) {
if (fimc->id == 1 && fimc->variant->pix_hoff)
f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
&ctx->s_frame : &ctx->d_frame;
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
spin_lock_irqsave(&ctx->slock, flags);
if (~ctx->state & (FIMC_SRC_FMT | FIMC_DST_FMT)) {
/* Check to see if scaling ratio is within supported range */
else
ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame);
if (ret) {
- spin_unlock_irqrestore(&ctx->slock, flags);
v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
- return -EINVAL;
+ ret = -EINVAL;
+ goto scr_unlock;
}
}
ctx->state |= FIMC_PARAMS;
f->width = cr->c.width;
f->height = cr->c.height;
+scr_unlock:
spin_unlock_irqrestore(&ctx->slock, flags);
+ mutex_unlock(&fimc->lock);
return 0;
}
.vidioc_g_ctrl = fimc_vidioc_g_ctrl,
.vidioc_s_ctrl = fimc_m2m_s_ctrl,
- .vidioc_g_crop = fimc_vidioc_g_crop,
+ .vidioc_g_crop = fimc_m2m_g_crop,
.vidioc_s_crop = fimc_m2m_s_crop,
- .vidioc_cropcap = fimc_vidioc_cropcap
+ .vidioc_cropcap = fimc_m2m_cropcap
};
.open = fimc_m2m_open,
.release = fimc_m2m_release,
.poll = fimc_m2m_poll,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = fimc_m2m_mmap,
};
.pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
+ .has_cistatus2 = 1,
.min_inp_pixsize = 16,
.min_out_pixsize = 16,
.hor_offs_align = 1,
static struct samsung_fimc_variant fimc2_variant_s5pv310 = {
.pix_hoff = 1,
+ .has_cistatus2 = 1,
.min_inp_pixsize = 16,
.min_out_pixsize = 16,
.hor_offs_align = 1,
/*#define DEBUG*/
+#include <linux/sched.h>
#include <linux/types.h>
+#include <linux/videodev2.h>
#include <media/videobuf-core.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mem2mem.h>
#include <media/v4l2-mediabus.h>
#include <media/s3c_fimc.h>
-#include <linux/videodev2.h>
+
#include "regs-fimc.h"
#define err(fmt, args...) \
* @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
* @has_inp_rot: set if has input rotator
* @has_out_rot: set if has output rotator
+ * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision
* @pix_limit: pixel size constraints for the scaler
* @min_inp_pixsize: minimum input pixel size
* @min_out_pixsize: minimum output pixel size
unsigned int pix_hoff:1;
unsigned int has_inp_rot:1;
unsigned int has_out_rot:1;
+ unsigned int has_cistatus2:1;
struct fimc_pix_limit *pix_limit;
u16 min_inp_pixsize;
u16 min_out_pixsize;
return frame;
}
+/* Return an index to the buffer actually being written. */
static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
{
- u32 reg = readl(dev->regs + S5P_CISTATUS);
- return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
- S5P_CISTATUS_FRAMECNT_SHIFT;
+ u32 reg;
+
+ if (dev->variant->has_cistatus2) {
+ reg = readl(dev->regs + S5P_CISTATUS2) & 0x3F;
+ return reg > 0 ? --reg : reg;
+ } else {
+ reg = readl(dev->regs + S5P_CISTATUS);
+ return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
+ S5P_CISTATUS_FRAMECNT_SHIFT;
+ }
}
/* -----------------------------------------------------*/
struct v4l2_format *f);
int fimc_vidioc_try_fmt(struct file *file, void *priv,
struct v4l2_format *f);
-int fimc_vidioc_g_crop(struct file *file, void *fh,
- struct v4l2_crop *cr);
-int fimc_vidioc_cropcap(struct file *file, void *fh,
- struct v4l2_cropcap *cr);
int fimc_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc);
int fimc_vidioc_g_ctrl(struct file *file, void *priv,
#define S5P_CISTATUS_VVALID_A (1 << 15)
#define S5P_CISTATUS_VVALID_B (1 << 14)
+/* Indexes to the last and the currently processed buffer. */
+#define S5P_CISTATUS2 0x68
+
/* Image capture control */
#define S5P_CIIMGCPT 0xc0
#define S5P_CIIMGCPT_IMGCPTEN (1 << 31)
* we complete the completion.
*/
- if (!csi2->driver || !csi2->driver->owner) {
+ if (!csi2->driver) {
complete(&wait.completion);
/* Either too late, or probing failed */
bus_unregister_notifier(&platform_bus_type, &wait.notifier);
int pix_idx;
struct videobuf_buffer *active;
enum sh_vou_status status;
+ struct mutex fop_lock;
};
struct sh_vou_file {
vb->state = VIDEOBUF_NEEDS_INIT;
}
-/* Locking: caller holds vq->vb_lock mutex */
+/* Locking: caller holds fop_lock mutex */
static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
return 0;
}
-/* Locking: caller holds vq->vb_lock mutex */
+/* Locking: caller holds fop_lock mutex */
static int sh_vou_buf_prepare(struct videobuf_queue *vq,
struct videobuf_buffer *vb,
enum v4l2_field field)
return 0;
}
-/* Locking: caller holds vq->vb_lock mutex and vq->irqlock spinlock */
+/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */
static void sh_vou_buf_queue(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
V4L2_BUF_TYPE_VIDEO_OUTPUT,
V4L2_FIELD_NONE,
sizeof(struct videobuf_buffer), vdev,
- NULL);
+ &vou_dev->fop_lock);
return 0;
}
.owner = THIS_MODULE,
.open = sh_vou_open,
.release = sh_vou_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = sh_vou_mmap,
.poll = sh_vou_poll,
};
INIT_LIST_HEAD(&vou_dev->queue);
spin_lock_init(&vou_dev->lock);
+ mutex_init(&vou_dev->fop_lock);
atomic_set(&vou_dev->use_count, 0);
vou_dev->pdata = vou_pdata;
vou_dev->status = SH_VOU_IDLE;
vdev->tvnorms |= V4L2_STD_PAL;
vdev->v4l2_dev = &vou_dev->v4l2_dev;
vdev->release = video_device_release;
+ vdev->lock = &vou_dev->fop_lock;
vou_dev->vdev = vdev;
video_set_drvdata(vdev, vou_dev);
.owner = THIS_MODULE,
.open = sn9c102_open,
.release = sn9c102_release,
- .ioctl = sn9c102_ioctl,
+ .unlocked_ioctl = sn9c102_ioctl,
.read = sn9c102_read,
.poll = sn9c102_poll,
.mmap = sn9c102_mmap,
ret = soc_camera_set_fmt(icd, &f);
if (ret < 0)
goto esfmt;
+
+ ici->ops->init_videobuf(&icd->vb_vidq, icd);
}
file->private_data = icd;
dev_dbg(&icd->dev, "camera device open\n");
- ici->ops->init_videobuf(&icd->vb_vidq, icd);
-
mutex_unlock(&icd->video_lock);
return 0;
}
}
-struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
+static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
__u32 v4l2_id, struct uvc_control_mapping **mapping)
{
struct uvc_control *ctrl = NULL;
return ret;
}
+/*
+ * Mapping V4L2 controls to UVC controls can be straighforward if done well.
+ * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
+ * must be grouped (for instance the Red Balance, Blue Balance and Do White
+ * Balance V4L2 controls use the White Balance Component UVC control) or
+ * otherwise translated. The approach we take here is to use a translation
+ * table for the controls that can be mapped directly, and handle the others
+ * manually.
+ */
+int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
+ struct v4l2_querymenu *query_menu)
+{
+ struct uvc_menu_info *menu_info;
+ struct uvc_control_mapping *mapping;
+ struct uvc_control *ctrl;
+ u32 index = query_menu->index;
+ u32 id = query_menu->id;
+ int ret;
+
+ memset(query_menu, 0, sizeof(*query_menu));
+ query_menu->id = id;
+ query_menu->index = index;
+
+ ret = mutex_lock_interruptible(&chain->ctrl_mutex);
+ if (ret < 0)
+ return -ERESTARTSYS;
+
+ ctrl = uvc_find_control(chain, query_menu->id, &mapping);
+ if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (query_menu->index >= mapping->menu_count) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ menu_info = &mapping->menu_info[query_menu->index];
+ strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
+
+done:
+ mutex_unlock(&chain->ctrl_mutex);
+ return ret;
+}
+
/* --------------------------------------------------------------------------
* Control transactions
}
/*
+ * Free the video buffers.
+ *
+ * This function must be called with the queue lock held.
+ */
+static int __uvc_free_buffers(struct uvc_video_queue *queue)
+{
+ unsigned int i;
+
+ for (i = 0; i < queue->count; ++i) {
+ if (queue->buffer[i].vma_use_count != 0)
+ return -EBUSY;
+ }
+
+ if (queue->count) {
+ vfree(queue->mem);
+ queue->count = 0;
+ }
+
+ return 0;
+}
+
+int uvc_free_buffers(struct uvc_video_queue *queue)
+{
+ int ret;
+
+ mutex_lock(&queue->mutex);
+ ret = __uvc_free_buffers(queue);
+ mutex_unlock(&queue->mutex);
+
+ return ret;
+}
+
+/*
* Allocate the video buffers.
*
* Pages are reserved to make sure they will not be swapped, as they will be
mutex_lock(&queue->mutex);
- if ((ret = uvc_free_buffers(queue)) < 0)
+ if ((ret = __uvc_free_buffers(queue)) < 0)
goto done;
/* Bail out if no buffers should be allocated. */
}
/*
- * Free the video buffers.
- *
- * This function must be called with the queue lock held.
- */
-int uvc_free_buffers(struct uvc_video_queue *queue)
-{
- unsigned int i;
-
- for (i = 0; i < queue->count; ++i) {
- if (queue->buffer[i].vma_use_count != 0)
- return -EBUSY;
- }
-
- if (queue->count) {
- vfree(queue->mem);
- queue->count = 0;
- }
-
- return 0;
-}
-
-/*
* Check if buffers have been allocated.
*/
int uvc_queue_allocated(struct uvc_video_queue *queue)
}
/*
+ * VMA operations.
+ */
+static void uvc_vm_open(struct vm_area_struct *vma)
+{
+ struct uvc_buffer *buffer = vma->vm_private_data;
+ buffer->vma_use_count++;
+}
+
+static void uvc_vm_close(struct vm_area_struct *vma)
+{
+ struct uvc_buffer *buffer = vma->vm_private_data;
+ buffer->vma_use_count--;
+}
+
+static const struct vm_operations_struct uvc_vm_ops = {
+ .open = uvc_vm_open,
+ .close = uvc_vm_close,
+};
+
+/*
+ * Memory-map a video buffer.
+ *
+ * This function implements video buffers memory mapping and is intended to be
+ * used by the device mmap handler.
+ */
+int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
+{
+ struct uvc_buffer *uninitialized_var(buffer);
+ struct page *page;
+ unsigned long addr, start, size;
+ unsigned int i;
+ int ret = 0;
+
+ start = vma->vm_start;
+ size = vma->vm_end - vma->vm_start;
+
+ mutex_lock(&queue->mutex);
+
+ for (i = 0; i < queue->count; ++i) {
+ buffer = &queue->buffer[i];
+ if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+
+ if (i == queue->count || size != queue->buf_size) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * VM_IO marks the area as being an mmaped region for I/O to a
+ * device. It also prevents the region from being core dumped.
+ */
+ vma->vm_flags |= VM_IO;
+
+ addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+ while (size > 0) {
+ page = vmalloc_to_page((void *)addr);
+ if ((ret = vm_insert_page(vma, start, page)) < 0)
+ goto done;
+
+ start += PAGE_SIZE;
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vma->vm_ops = &uvc_vm_ops;
+ vma->vm_private_data = buffer;
+ uvc_vm_open(vma);
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
* Poll the video queue.
*
* This function implements video queue polling and is intended to be used by
*/
/*
- * Mapping V4L2 controls to UVC controls can be straighforward if done well.
- * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
- * must be grouped (for instance the Red Balance, Blue Balance and Do White
- * Balance V4L2 controls use the White Balance Component UVC control) or
- * otherwise translated. The approach we take here is to use a translation
- * table for the controls that can be mapped directly, and handle the others
- * manually.
- */
-static int uvc_v4l2_query_menu(struct uvc_video_chain *chain,
- struct v4l2_querymenu *query_menu)
-{
- struct uvc_menu_info *menu_info;
- struct uvc_control_mapping *mapping;
- struct uvc_control *ctrl;
- u32 index = query_menu->index;
- u32 id = query_menu->id;
-
- ctrl = uvc_find_control(chain, query_menu->id, &mapping);
- if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
- return -EINVAL;
-
- if (query_menu->index >= mapping->menu_count)
- return -EINVAL;
-
- memset(query_menu, 0, sizeof(*query_menu));
- query_menu->id = id;
- query_menu->index = index;
-
- menu_info = &mapping->menu_info[query_menu->index];
- strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
- return 0;
-}
-
-/*
* Find the frame interval closest to the requested frame interval for the
* given frame format and size. This should be done by the device as part of
* the Video Probe and Commit negotiation, but some hardware don't implement
* developers test their webcams with the Linux driver as well as with
* the Windows driver).
*/
+ mutex_lock(&stream->mutex);
if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
probe->dwMaxVideoFrameSize =
stream->ctrl.dwMaxVideoFrameSize;
/* Probe the device. */
ret = uvc_probe_video(stream, probe);
+ mutex_unlock(&stream->mutex);
if (ret < 0)
goto done;
static int uvc_v4l2_get_format(struct uvc_streaming *stream,
struct v4l2_format *fmt)
{
- struct uvc_format *format = stream->cur_format;
- struct uvc_frame *frame = stream->cur_frame;
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+ int ret = 0;
if (fmt->type != stream->type)
return -EINVAL;
- if (format == NULL || frame == NULL)
- return -EINVAL;
+ mutex_lock(&stream->mutex);
+ format = stream->cur_format;
+ frame = stream->cur_frame;
+
+ if (format == NULL || frame == NULL) {
+ ret = -EINVAL;
+ goto done;
+ }
fmt->fmt.pix.pixelformat = format->fcc;
fmt->fmt.pix.width = frame->wWidth;
fmt->fmt.pix.colorspace = format->colorspace;
fmt->fmt.pix.priv = 0;
- return 0;
+done:
+ mutex_unlock(&stream->mutex);
+ return ret;
}
static int uvc_v4l2_set_format(struct uvc_streaming *stream,
if (fmt->type != stream->type)
return -EINVAL;
- if (uvc_queue_allocated(&stream->queue))
- return -EBUSY;
-
ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
if (ret < 0)
return ret;
+ mutex_lock(&stream->mutex);
+
+ if (uvc_queue_allocated(&stream->queue)) {
+ ret = -EBUSY;
+ goto done;
+ }
+
memcpy(&stream->ctrl, &probe, sizeof probe);
stream->cur_format = format;
stream->cur_frame = frame;
- return 0;
+done:
+ mutex_unlock(&stream->mutex);
+ return ret;
}
static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
if (parm->type != stream->type)
return -EINVAL;
+ mutex_lock(&stream->mutex);
numerator = stream->ctrl.dwFrameInterval;
+ mutex_unlock(&stream->mutex);
+
denominator = 10000000;
uvc_simplify_fraction(&numerator, &denominator, 8, 333);
static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
struct v4l2_streamparm *parm)
{
- struct uvc_frame *frame = stream->cur_frame;
struct uvc_streaming_control probe;
struct v4l2_fract timeperframe;
uint32_t interval;
if (parm->type != stream->type)
return -EINVAL;
- if (uvc_queue_streaming(&stream->queue))
- return -EBUSY;
-
if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
timeperframe = parm->parm.capture.timeperframe;
else
timeperframe = parm->parm.output.timeperframe;
- memcpy(&probe, &stream->ctrl, sizeof probe);
interval = uvc_fraction_to_interval(timeperframe.numerator,
timeperframe.denominator);
-
uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
timeperframe.numerator, timeperframe.denominator, interval);
- probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
+
+ mutex_lock(&stream->mutex);
+
+ if (uvc_queue_streaming(&stream->queue)) {
+ mutex_unlock(&stream->mutex);
+ return -EBUSY;
+ }
+
+ memcpy(&probe, &stream->ctrl, sizeof probe);
+ probe.dwFrameInterval =
+ uvc_try_frame_interval(stream->cur_frame, interval);
/* Probe the device with the new settings. */
ret = uvc_probe_video(stream, &probe);
- if (ret < 0)
+ if (ret < 0) {
+ mutex_unlock(&stream->mutex);
return ret;
+ }
memcpy(&stream->ctrl, &probe, sizeof probe);
+ mutex_unlock(&stream->mutex);
/* Return the actual frame period. */
timeperframe.numerator = probe.dwFrameInterval;
if (uvc_has_privileges(handle)) {
uvc_video_enable(stream, 0);
- mutex_lock(&stream->queue.mutex);
if (uvc_free_buffers(&stream->queue) < 0)
uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
"free buffers.\n");
- mutex_unlock(&stream->queue.mutex);
}
/* Release the file handle. */
}
case VIDIOC_QUERYMENU:
- return uvc_v4l2_query_menu(chain, arg);
+ return uvc_query_v4l2_menu(chain, arg);
case VIDIOC_G_EXT_CTRLS:
{
case VIDIOC_CROPCAP:
{
struct v4l2_cropcap *ccap = arg;
- struct uvc_frame *frame = stream->cur_frame;
if (ccap->type != stream->type)
return -EINVAL;
ccap->bounds.left = 0;
ccap->bounds.top = 0;
- ccap->bounds.width = frame->wWidth;
- ccap->bounds.height = frame->wHeight;
+
+ mutex_lock(&stream->mutex);
+ ccap->bounds.width = stream->cur_frame->wWidth;
+ ccap->bounds.height = stream->cur_frame->wHeight;
+ mutex_unlock(&stream->mutex);
ccap->defrect = ccap->bounds;
case VIDIOC_REQBUFS:
{
struct v4l2_requestbuffers *rb = arg;
- unsigned int bufsize =
- stream->ctrl.dwMaxVideoFrameSize;
if (rb->type != stream->type ||
rb->memory != V4L2_MEMORY_MMAP)
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
- ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize);
+ mutex_lock(&stream->mutex);
+ ret = uvc_alloc_buffers(&stream->queue, rb->count,
+ stream->ctrl.dwMaxVideoFrameSize);
+ mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
if (!uvc_has_privileges(handle))
return -EBUSY;
+ mutex_lock(&stream->mutex);
ret = uvc_video_enable(stream, 1);
+ mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
break;
return -EINVAL;
}
-/*
- * VMA operations.
- */
-static void uvc_vm_open(struct vm_area_struct *vma)
-{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count++;
-}
-
-static void uvc_vm_close(struct vm_area_struct *vma)
-{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count--;
-}
-
-static const struct vm_operations_struct uvc_vm_ops = {
- .open = uvc_vm_open,
- .close = uvc_vm_close,
-};
-
static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
{
struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
- struct uvc_video_queue *queue = &stream->queue;
- struct uvc_buffer *uninitialized_var(buffer);
- struct page *page;
- unsigned long addr, start, size;
- unsigned int i;
- int ret = 0;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n");
- start = vma->vm_start;
- size = vma->vm_end - vma->vm_start;
-
- mutex_lock(&queue->mutex);
-
- for (i = 0; i < queue->count; ++i) {
- buffer = &queue->buffer[i];
- if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
-
- if (i == queue->count || size != queue->buf_size) {
- ret = -EINVAL;
- goto done;
- }
-
- /*
- * VM_IO marks the area as being an mmaped region for I/O to a
- * device. It also prevents the region from being core dumped.
- */
- vma->vm_flags |= VM_IO;
-
- addr = (unsigned long)queue->mem + buffer->buf.m.offset;
- while (size > 0) {
- page = vmalloc_to_page((void *)addr);
- if ((ret = vm_insert_page(vma, start, page)) < 0)
- goto done;
-
- start += PAGE_SIZE;
- addr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vma->vm_ops = &uvc_vm_ops;
- vma->vm_private_data = buffer;
- uvc_vm_open(vma);
-
-done:
- mutex_unlock(&queue->mutex);
- return ret;
+ return uvc_queue_mmap(&stream->queue, vma);
}
static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
- .ioctl = uvc_v4l2_ioctl,
+ .unlocked_ioctl = uvc_v4l2_ioctl,
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
unsigned int i;
int ret;
- mutex_lock(&stream->mutex);
-
/* Perform probing. The device should adjust the requested values
* according to its capabilities. However, some devices, namely the
* first generation UVC Logitech webcams, don't implement the Video
}
done:
- mutex_unlock(&stream->mutex);
return ret;
}
struct uvc_streaming_control ctrl;
struct uvc_format *cur_format;
struct uvc_frame *cur_frame;
-
+ /* Protect access to ctrl, cur_format, cur_frame and hardware video
+ * probe control.
+ */
struct mutex mutex;
unsigned int frozen : 1;
extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
struct uvc_buffer *buf);
+extern int uvc_queue_mmap(struct uvc_video_queue *queue,
+ struct vm_area_struct *vma);
extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
struct file *file, poll_table *wait);
extern int uvc_queue_allocated(struct uvc_video_queue *queue);
extern int uvc_status_resume(struct uvc_device *dev);
/* Controls */
-extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
- __u32 v4l2_id, struct uvc_control_mapping **mapping);
extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl);
+extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
+ struct v4l2_querymenu *query_menu);
extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
const struct uvc_control_mapping *mapping);
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
- int ret = -EIO;
+ int ret = -ENODEV;
if (!vdev->fops->read)
return -EINVAL;
- if (vdev->lock)
- mutex_lock(vdev->lock);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->read(filp, buf, sz, off);
if (vdev->lock)
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
- int ret = -EIO;
+ int ret = -ENODEV;
if (!vdev->fops->write)
return -EINVAL;
- if (vdev->lock)
- mutex_lock(vdev->lock);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->write(filp, buf, sz, off);
if (vdev->lock)
static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
{
struct video_device *vdev = video_devdata(filp);
- int ret = DEFAULT_POLLMASK;
+ int ret = POLLERR | POLLHUP;
if (!vdev->fops->poll)
- return ret;
+ return DEFAULT_POLLMASK;
if (vdev->lock)
mutex_lock(vdev->lock);
if (video_is_registered(vdev))
int ret = -ENODEV;
if (vdev->fops->unlocked_ioctl) {
- if (vdev->lock)
- mutex_lock(vdev->lock);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
if (vdev->lock)
mutex_unlock(vdev->lock);
} else if (vdev->fops->ioctl) {
- /* TODO: convert all drivers to unlocked_ioctl */
+ /* This code path is a replacement for the BKL. It is a major
+ * hack but it will have to do for those drivers that are not
+ * yet converted to use unlocked_ioctl.
+ *
+ * There are two options: if the driver implements struct
+ * v4l2_device, then the lock defined there is used to
+ * serialize the ioctls. Otherwise the v4l2 core lock defined
+ * below is used. This lock is really bad since it serializes
+ * completely independent devices.
+ *
+ * Both variants suffer from the same problem: if the driver
+ * sleeps, then it blocks all ioctls since the lock is still
+ * held. This is very common for VIDIOC_DQBUF since that
+ * normally waits for a frame to arrive. As a result any other
+ * ioctl calls will proceed very, very slowly since each call
+ * will have to wait for the VIDIOC_QBUF to finish. Things that
+ * should take 0.01s may now take 10-20 seconds.
+ *
+ * The workaround is to *not* take the lock for VIDIOC_DQBUF.
+ * This actually works OK for videobuf-based drivers, since
+ * videobuf will take its own internal lock.
+ */
static DEFINE_MUTEX(v4l2_ioctl_mutex);
+ struct mutex *m = vdev->v4l2_dev ?
+ &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex;
- mutex_lock(&v4l2_ioctl_mutex);
+ if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
+ return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->ioctl(filp, cmd, arg);
- mutex_unlock(&v4l2_ioctl_mutex);
+ if (cmd != VIDIOC_DQBUF)
+ mutex_unlock(m);
} else
ret = -ENOTTY;
if (!vdev->fops->mmap)
return ret;
- if (vdev->lock)
- mutex_lock(vdev->lock);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->mmap(filp, vm);
if (vdev->lock)
mutex_lock(&videodev_lock);
vdev = video_devdata(filp);
/* return ENODEV if the video device has already been removed. */
- if (vdev == NULL) {
+ if (vdev == NULL || !video_is_registered(vdev)) {
mutex_unlock(&videodev_lock);
return -ENODEV;
}
video_get(vdev);
mutex_unlock(&videodev_lock);
if (vdev->fops->open) {
- if (vdev->lock)
- mutex_lock(vdev->lock);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
+ ret = -ERESTARTSYS;
+ goto err;
+ }
if (video_is_registered(vdev))
ret = vdev->fops->open(filp);
else
mutex_unlock(vdev->lock);
}
+err:
/* decrease the refcount in case of an error */
if (ret)
video_put(vdev);
if (!vdev || !video_is_registered(vdev))
return;
+ mutex_lock(&videodev_lock);
+ /* This must be in a critical section to prevent a race with v4l2_open.
+ * Once this bit has been cleared video_get may never be called again.
+ */
clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
+ mutex_unlock(&videodev_lock);
device_unregister(&vdev->dev);
}
EXPORT_SYMBOL(video_unregister_device);
INIT_LIST_HEAD(&v4l2_dev->subdevs);
spin_lock_init(&v4l2_dev->lock);
+ mutex_init(&v4l2_dev->ioctl_lock);
v4l2_dev->dev = dev;
if (dev == NULL) {
/* If dev == NULL, then name must be filled in by the caller */
static const struct v4l2_file_operations w9966_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = w9966_v4l_read,
};
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
-#include <media/wm8775.h>
MODULE_DESCRIPTION("wm8775 driver");
MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
TOT_REGS
};
-#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */
-#define ALC_EN 0x100 /* R17: ALC enable */
-
struct wm8775_state {
struct v4l2_subdev sd;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl *mute;
- struct v4l2_ctrl *vol;
- struct v4l2_ctrl *bal;
- struct v4l2_ctrl *loud;
u8 input; /* Last selected input (0-0xf) */
};
return -1;
}
-static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly)
-{
- struct wm8775_state *state = to_state(sd);
- u8 vol_l, vol_r;
- int muted = 0 != state->mute->val;
- u16 volume = (u16)state->vol->val;
- u16 balance = (u16)state->bal->val;
-
- /* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
- vol_l = (min(65536 - balance, 32768) * volume) >> 23;
- vol_r = (min(balance, (u16)32768) * volume) >> 23;
-
- /* Mute */
- if (muted || quietly)
- wm8775_write(sd, R21, 0x0c0 | state->input);
-
- wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */
- wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */
-
- /* Un-mute */
- if (!muted)
- wm8775_write(sd, R21, state->input);
-}
-
static int wm8775_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
state->input = input;
if (!v4l2_ctrl_g_ctrl(state->mute))
return 0;
- if (!v4l2_ctrl_g_ctrl(state->vol))
- return 0;
- if (!v4l2_ctrl_g_ctrl(state->bal))
- return 0;
- wm8775_set_audio(sd, 1);
+ wm8775_write(sd, R21, 0x0c0);
+ wm8775_write(sd, R14, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
+ wm8775_write(sd, R21, 0x100 + state->input);
return 0;
}
static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_sd(ctrl);
+ struct wm8775_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- wm8775_set_audio(sd, 0);
- return 0;
- case V4L2_CID_AUDIO_LOUDNESS:
- wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD);
+ wm8775_write(sd, R21, 0x0c0);
+ wm8775_write(sd, R14, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
+ if (!ctrl->val)
+ wm8775_write(sd, R21, 0x100 + state->input);
return 0;
}
return -EINVAL;
static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
{
- wm8775_set_audio(sd, 0);
+ struct wm8775_state *state = to_state(sd);
+
+ /* If I remove this, then it can happen that I have no
+ sound the first time I tune from static to a valid channel.
+ It's difficult to reproduce and is almost certainly related
+ to the zero cross detect circuit. */
+ wm8775_write(sd, R21, 0x0c0);
+ wm8775_write(sd, R14, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
+ wm8775_write(sd, R21, 0x100 + state->input);
return 0;
}
{
struct wm8775_state *state;
struct v4l2_subdev *sd;
- int err;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENOMEM;
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
- sd->grp_id = WM8775_GID; /* subdev group id */
state->input = 2;
- v4l2_ctrl_handler_init(&state->hdl, 4);
+ v4l2_ctrl_handler_init(&state->hdl, 1);
state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
- state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
- V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/
- state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
- V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768);
- state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
- V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1);
sd->ctrl_handler = &state->hdl;
- err = state->hdl.error;
- if (err) {
+ if (state->hdl.error) {
+ int err = state->hdl.error;
+
v4l2_ctrl_handler_free(&state->hdl);
kfree(state);
return err;
wm8775_write(sd, R23, 0x000);
/* Disable zero cross detect timeout */
wm8775_write(sd, R7, 0x000);
- /* HPF enable, I2S mode, 24-bit */
- wm8775_write(sd, R11, 0x022);
+ /* Left justified, 24-bit mode */
+ wm8775_write(sd, R11, 0x021);
/* Master mode, clock ratio 256fs */
wm8775_write(sd, R12, 0x102);
/* Powered up */
wm8775_write(sd, R13, 0x000);
- /* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */
- wm8775_write(sd, R16, 0x1bb);
- /* Set ALC mode and hold time */
- wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD);
+ /* ADC gain +2.5dB, enable zero cross */
+ wm8775_write(sd, R14, 0x1d4);
+ /* ADC gain +2.5dB, enable zero cross */
+ wm8775_write(sd, R15, 0x1d4);
+ /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
+ wm8775_write(sd, R16, 0x1bf);
+ /* Enable gain control, use zero cross detection,
+ ALC hold time 42.6 ms */
+ wm8775_write(sd, R17, 0x185);
/* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
wm8775_write(sd, R18, 0x0a2);
/* Enable noise gate, threshold -72dBfs */
wm8775_write(sd, R19, 0x005);
- /* Transient window 4ms, ALC min gain -5dB */
- wm8775_write(sd, R20, 0x0fb);
-
- wm8775_set_audio(sd, 1); /* set volume/mute/mux */
-
+ /* Transient window 4ms, lower PGA gain limit -1dB */
+ wm8775_write(sd, R20, 0x07a);
+ /* LRBOTH = 1, use input 2. */
+ wm8775_write(sd, R21, 0x102);
return 0;
}
continue;
do {
- int bit = __ffs(status);
+ int bit = __ffs(value);
int line = i * 8 + bit;
handle_nested_irq(ab8500->irq_base + line);
dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
goto err;
}
- if (ret != 0x6204) {
+ switch (ret) {
+ case 0x6204:
+ case 0x6246:
+ break;
+ default:
dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
ret = -EINVAL;
goto err;
case WM8325:
ret = mfd_add_devices(wm831x->dev, -1,
wm8320_devs, ARRAY_SIZE(wm8320_devs),
- NULL, 0);
+ NULL, wm831x->irq_base);
break;
default:
case PM_POST_SUSPEND:
case PM_POST_HIBERNATION:
+ case PM_POST_RESTORE:
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 0;
#include <linux/highmem.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/sdio.h>
#include <asm/io.h>
#include <asm/irq.h>
else if (data->flags & MMC_DATA_WRITE)
cmdr |= AT91_MCI_TRCMD_START;
- if (data->flags & MMC_DATA_STREAM)
- cmdr |= AT91_MCI_TRTYP_STREAM;
- if (data->blocks > 1)
- cmdr |= AT91_MCI_TRTYP_MULTIPLE;
+ if (cmd->opcode == SD_IO_RW_EXTENDED) {
+ cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK;
+ } else {
+ if (data->flags & MMC_DATA_STREAM)
+ cmdr |= AT91_MCI_TRTYP_STREAM;
+ if (data->blocks > 1)
+ cmdr |= AT91_MCI_TRTYP_MULTIPLE;
+ }
}
else {
block_length = 0;
#include <linux/stat.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/sdio.h>
#include <mach/atmel-mci.h>
#include <linux/atmel-mci.h>
data = cmd->data;
if (data) {
cmdr |= MCI_CMDR_START_XFER;
- if (data->flags & MMC_DATA_STREAM)
- cmdr |= MCI_CMDR_STREAM;
- else if (data->blocks > 1)
- cmdr |= MCI_CMDR_MULTI_BLOCK;
- else
- cmdr |= MCI_CMDR_BLOCK;
+
+ if (cmd->opcode == SD_IO_RW_EXTENDED) {
+ cmdr |= MCI_CMDR_SDIO_BLOCK;
+ } else {
+ if (data->flags & MMC_DATA_STREAM)
+ cmdr |= MCI_CMDR_STREAM;
+ else if (data->blocks > 1)
+ cmdr |= MCI_CMDR_MULTI_BLOCK;
+ else
+ cmdr |= MCI_CMDR_BLOCK;
+ }
if (data->flags & MMC_DATA_READ)
cmdr |= MCI_CMDR_TRDIR_READ;
adapter->wol = 0;
+ device_set_wakeup_enable(&pdev->dev, false);
adapter->link_speed = SPEED_0;
adapter->link_duplex = FULL_DUPLEX;
adapter->num_rx_queues = AT_DEF_RECEIVE_QUEUE;
return 0;
}
-static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
+static int atl1c_suspend(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
struct atl1c_adapter *adapter = netdev_priv(netdev);
struct atl1c_hw *hw = &adapter->hw;
u32 wol_ctrl_data = 0;
u16 mii_intr_status_data = 0;
u32 wufc = adapter->wol;
- int retval = 0;
atl1c_disable_l0s_l1(hw);
if (netif_running(netdev)) {
atl1c_down(adapter);
}
netif_device_detach(netdev);
- retval = pci_save_state(pdev);
- if (retval)
- return retval;
if (wufc)
if (atl1c_phy_power_saving(hw) != 0)
AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data);
AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
- /* pcie patch */
- device_set_wakeup_enable(&pdev->dev, 1);
-
AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT |
GPHY_CTRL_EXT_RESET);
- pci_prepare_to_sleep(pdev);
} else {
AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_POWER_SAVING);
master_ctrl_data |= MASTER_CTRL_CLK_SEL_DIS;
AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
hw->phy_configured = false; /* re-init PHY when resume */
- pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
}
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
return 0;
}
-static int atl1c_resume(struct pci_dev *pdev)
+static int atl1c_resume(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
struct atl1c_adapter *adapter = netdev_priv(netdev);
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- pci_enable_wake(pdev, PCI_D3hot, 0);
- pci_enable_wake(pdev, PCI_D3cold, 0);
-
AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE |
ATL1C_PCIE_PHY_RESET);
static void atl1c_shutdown(struct pci_dev *pdev)
{
- atl1c_suspend(pdev, PMSG_SUSPEND);
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+ atl1c_suspend(&pdev->dev);
+ pci_wake_from_d3(pdev, adapter->wol);
+ pci_set_power_state(pdev, PCI_D3hot);
}
static const struct net_device_ops atl1c_netdev_ops = {
.resume = atl1c_io_resume,
};
+static SIMPLE_DEV_PM_OPS(atl1c_pm_ops, atl1c_suspend, atl1c_resume);
+
static struct pci_driver atl1c_driver = {
.name = atl1c_driver_name,
.id_table = atl1c_pci_tbl,
.probe = atl1c_probe,
.remove = __devexit_p(atl1c_remove),
- /* Power Managment Hooks */
- .suspend = atl1c_suspend,
- .resume = atl1c_resume,
.shutdown = atl1c_shutdown,
- .err_handler = &atl1c_err_handler
+ .err_handler = &atl1c_err_handler,
+ .driver.pm = &atl1c_pm_ops,
};
/*
struct atl1_rfd_ring rfd_old, rfd_new;
struct atl1_rrd_ring rrd_old, rrd_new;
struct atl1_ring_header rhdr_old, rhdr_new;
+ struct atl1_smb smb;
+ struct atl1_cmb cmb;
int err;
tpd_old = adapter->tpd_ring;
adapter->rrd_ring = rrd_old;
adapter->tpd_ring = tpd_old;
adapter->ring_header = rhdr_old;
+ /*
+ * Save SMB and CMB, since atl1_free_ring_resources
+ * will clear them.
+ */
+ smb = adapter->smb;
+ cmb = adapter->cmb;
atl1_free_ring_resources(adapter);
adapter->rfd_ring = rfd_new;
adapter->rrd_ring = rrd_new;
adapter->tpd_ring = tpd_new;
adapter->ring_header = rhdr_new;
+ adapter->smb = smb;
+ adapter->cmb = cmb;
err = atl1_up(adapter);
if (err)
u8 __iomem *db; /* Door Bell */
u8 __iomem *pcicfg; /* PCI config space */
- spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */
+ struct mutex mbox_lock; /* For serializing mbox cmds to BE card */
struct be_dma_mem mbox_mem;
/* Mbox mem is adjusted to align to 16 bytes. The allocated addr
* is stored for freeing purpose */
u8 *wrb;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = (u8 *)wrb_from_mbox(adapter);
*wrb++ = 0xFF;
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
if (adapter->eeh_err)
return -EIO;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = (u8 *)wrb_from_mbox(adapter);
*wrb++ = 0xFF;
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
int be_cmd_eq_create(struct be_adapter *adapter,
struct be_dma_mem *q_mem = &eq->dma_mem;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
eq->created = true;
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
struct be_cmd_req_mac_query *req;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
memcpy(mac_addr, resp->mac.addr, ETH_ALEN);
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
void *ctxt;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
cq->created = true;
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
void *ctxt;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
mccq->id = le16_to_cpu(resp->id);
mccq->created = true;
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
void *ctxt;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
txq->created = true;
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
struct be_dma_mem *q_mem = &rxq->dma_mem;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
*rss_id = resp->rss_id;
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
if (adapter->eeh_err)
return -EIO;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
struct be_cmd_req_if_create *req;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
*pmac_id = le32_to_cpu(resp->pmac_id);
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
if (adapter->eeh_err)
return -EIO;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
struct be_cmd_req_get_fw_version *req;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN);
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
struct be_cmd_req_query_fw_cfg *req;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
*caps = le32_to_cpu(resp->function_caps);
}
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
struct be_cmd_req_hdr *req;
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
u32 myhash[10];
int status;
- spin_lock(&adapter->mbox_lock);
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
status = be_mbox_notify_wait(adapter);
- spin_unlock(&adapter->mbox_lock);
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
}
memset(mc_cmd_mem->va, 0, mc_cmd_mem->size);
- spin_lock_init(&adapter->mbox_lock);
+ mutex_init(&adapter->mbox_lock);
spin_lock_init(&adapter->mcc_lock);
spin_lock_init(&adapter->mcc_cq_lock);
}
if (vlan_id) {
- skb = vlan_put_tag(skb, vlan_id);
+ /* The Ethernet header is not present yet, so it is
+ * too early to insert a VLAN tag. Force use of an
+ * out-of-line tag here and let dev_hard_start_xmit()
+ * insert it if the slave hardware can't.
+ */
+ skb = __vlan_hwaccel_put_tag(skb, vlan_id);
if (!skb) {
pr_err("failed to insert VLAN tag\n");
return;
* @bond: bond device that got this skb for tx.
* @skb: hw accel VLAN tagged skb to transmit
* @slave_dev: slave that is supposed to xmit this skbuff
- *
- * When the bond gets an skb to transmit that is
- * already hardware accelerated VLAN tagged, and it
- * needs to relay this skb to a slave that is not
- * hw accel capable, the skb needs to be "unaccelerated",
- * i.e. strip the hwaccel tag and re-insert it as part
- * of the payload.
*/
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
struct net_device *slave_dev)
{
- unsigned short uninitialized_var(vlan_id);
-
- /* Test vlan_list not vlgrp to catch and handle 802.1p tags */
- if (!list_empty(&bond->vlan_list) &&
- !(slave_dev->features & NETIF_F_HW_VLAN_TX) &&
- vlan_get_tag(skb, &vlan_id) == 0) {
- skb->dev = slave_dev;
- skb = vlan_put_tag(skb, vlan_id);
- if (!skb) {
- /* vlan_put_tag() frees the skb in case of error,
- * so return success here so the calling functions
- * won't attempt to free is again.
- */
- return 0;
- }
- } else {
- skb->dev = slave_dev;
- }
-
+ skb->dev = slave_dev;
skb->priority = 1;
#ifdef CONFIG_NET_POLL_CONTROLLER
if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) {
bond_do_fail_over_mac(bond, new_active,
old_active);
- bond->send_grat_arp = bond->params.num_grat_arp;
- bond_send_gratuitous_arp(bond);
+ if (netif_running(bond->dev)) {
+ bond->send_grat_arp = bond->params.num_grat_arp;
+ bond_send_gratuitous_arp(bond);
- bond->send_unsol_na = bond->params.num_unsol_na;
- bond_send_unsolicited_na(bond);
+ bond->send_unsol_na = bond->params.num_unsol_na;
+ bond_send_unsolicited_na(bond);
+ }
write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
/* resend IGMP joins since active slave has changed or
* all were sent on curr_active_slave */
- if ((USES_PRIMARY(bond->params.mode) && new_active) ||
- bond->params.mode == BOND_MODE_ROUNDROBIN) {
+ if (((USES_PRIMARY(bond->params.mode) && new_active) ||
+ bond->params.mode == BOND_MODE_ROUNDROBIN) &&
+ netif_running(bond->dev)) {
bond->igmp_retrans = bond->params.resend_igmp;
queue_delayed_work(bond->wq, &bond->mcast_work, 0);
}
bond_for_each_slave(bond, slave, i) {
if (slave->dev == slave_dev) {
- break;
+ return slave;
}
}
- return slave;
+ return 0;
}
static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
&udev->l2_ring_map,
GFP_KERNEL | __GFP_COMP);
if (!udev->l2_ring)
- return -ENOMEM;
+ goto err_udev;
udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size);
&udev->l2_buf_map,
GFP_KERNEL | __GFP_COMP);
if (!udev->l2_buf)
- return -ENOMEM;
+ goto err_dma;
write_lock(&cnic_dev_lock);
list_add(&udev->list, &cnic_udev_list);
cp->udev = udev;
return 0;
+ err_dma:
+ dma_free_coherent(&udev->pdev->dev, udev->l2_ring_size,
+ udev->l2_ring, udev->l2_ring_map);
+ err_udev:
+ kfree(udev);
+ return -ENOMEM;
}
static int cnic_init_uio(struct cnic_dev *dev)
static int ehea_set_flags(struct net_device *dev, u32 data)
{
+ /* Avoid changing the VLAN flags */
+ if ((data & (ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN)) !=
+ (ethtool_op_get_flags(dev) & (ETH_FLAG_RXVLAN |
+ ETH_FLAG_TXVLAN))){
+ return -EINVAL;
+ }
+
return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO
| ETH_FLAG_TXVLAN
| ETH_FLAG_RXVLAN);
/* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz + 2);
ep->rx_skbuff[i] = skb;
if (skb == NULL)
break;
entry = ep->dirty_rx % RX_RING_SIZE;
if (ep->rx_skbuff[entry] == NULL) {
struct sk_buff *skb;
- skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz);
+ skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz + 2);
if (skb == NULL)
break;
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
}
/* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz + 2);
hmp->rx_skbuff[i] = skb;
if (skb == NULL)
break;
entry = hmp->dirty_rx % RX_RING_SIZE;
desc = &(hmp->rx_ring[entry]);
if (hmp->rx_skbuff[entry] == NULL) {
- struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz + 2);
hmp->rx_skbuff[entry] = skb;
if (skb == NULL)
static struct pcmcia_device_id axnet_ids[] = {
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
+ PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530),
PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab),
PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110),
- PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041),
PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300),
}
#ifdef CONFIG_PPP_MULTILINK
+static bool mp_protocol_compress __read_mostly = true;
+module_param(mp_protocol_compress, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(mp_protocol_compress,
+ "compress protocol id in multilink fragments");
+
/*
* Divide a packet to be transmitted into fragments and
* send them out the individual links.
if (nfree == 0 || nfree < navail / 2)
return 0; /* can't take now, leave it in xmit_pending */
- /* Do protocol field compression (XXX this should be optional) */
+ /* Do protocol field compression */
p = skb->data;
len = skb->len;
- if (*p == 0) {
+ if (*p == 0 && mp_protocol_compress) {
++p;
--len;
}
bp->SharedMemAddr = pci_alloc_consistent(&bp->pdev,
bp->SharedMemSize,
&bp->SharedMemDMA);
- if (!bp->SharedMemSize) {
+ if (!bp->SharedMemAddr) {
printk("could not allocate mem for ");
printk("hardware module: %ld byte\n",
bp->SharedMemSize);
* This SUCKS.
* We need a much better method to determine if dma_addr_t is 64-bit.
*/
-#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT))
+#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || (defined(CONFIG_MIPS) && ((defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || defined(CONFIG_64BIT))) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT))
/* 64-bit dma_addr_t */
#define ADDR_64BITS /* This chip uses 64 bit addresses. */
#define netdrv_addr_t __le64
/* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + 2);
np->rx_skbuff[i] = skb;
if (skb == NULL)
break;
struct sk_buff *skb;
entry = np->dirty_rx % RX_RING_SIZE;
if (np->rx_skbuff[entry] == NULL) {
- skb = dev_alloc_skb(np->rx_buf_sz);
+ skb = dev_alloc_skb(np->rx_buf_sz + 2);
np->rx_skbuff[entry] = skb;
if (skb == NULL)
break; /* Better luck next round. */
ENTER;
master = READ_REG(priv, regINIT_SEMAPHORE);
if (!READ_REG(priv, regINIT_STATUS) && master) {
- rc = request_firmware(&fw, "tehuti/firmware.bin", &priv->pdev->dev);
+ rc = request_firmware(&fw, "tehuti/bdx.bin", &priv->pdev->dev);
if (rc)
goto out;
bdx_tx_push_desc_safe(priv, (char *)fw->data, fw->size);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(BDX_DRV_DESC);
-MODULE_FIRMWARE("tehuti/firmware.bin");
+MODULE_FIRMWARE("tehuti/bdx.bin");
cnt = pci_read_vpd(tp->pdev, pos,
TG3_NVM_VPD_LEN - pos,
&vpd_data[pos]);
- if (cnt == -ETIMEDOUT || -EINTR)
+ if (cnt == -ETIMEDOUT || cnt == -EINTR)
cnt = 0;
else if (cnt < 0)
goto out_not_found;
}
strcpy(info->driver, KBUILD_MODNAME);
- strcpy(info->version, UTS_RELEASE);
strcpy(info->bus_info, pci_name(pci_dev));
}
USB_DEVICE (0x0b95, 0x1780),
.driver_info = (unsigned long) &ax88178_info,
}, {
+ // Logitec LAN-GTJ/U2A
+ USB_DEVICE (0x0789, 0x0160),
+ .driver_info = (unsigned long) &ax88178_info,
+}, {
// Linksys USB200M Rev 2
USB_DEVICE (0x13b1, 0x0018),
.driver_info = (unsigned long) &ax88772_info,
/*
- * MOSCHIP MCS7830 based USB 2.0 Ethernet Devices
+ * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices
*
* based on usbnet.c, asix.c and the vendor provided mcs7830 driver
*
*
* Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!).
*
+ * 2010-12-19: add 7832 USB PID ("functionality same as MCS7830"),
+ * per active notification by manufacturer
+ *
* TODO:
* - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?)
* - implement ethtool_ops get_pauseparam/set_pauseparam
#define MCS7830_MAX_MCAST 64
#define MCS7830_VENDOR_ID 0x9710
+#define MCS7832_PRODUCT_ID 0x7832
#define MCS7830_PRODUCT_ID 0x7830
#define MCS7730_PRODUCT_ID 0x7730
if (!ret)
ret = mcs7830_write_phy(dev, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART );
- return ret < 0 ? : 0;
+ return ret;
}
}
static const struct driver_info moschip_info = {
- .description = "MOSCHIP 7830/7730 usb-NET adapter",
+ .description = "MOSCHIP 7830/7832/7730 usb-NET adapter",
.bind = mcs7830_bind,
.rx_fixup = mcs7830_rx_fixup,
.flags = FLAG_ETHER,
static const struct usb_device_id products[] = {
{
+ USB_DEVICE(MCS7830_VENDOR_ID, MCS7832_PRODUCT_ID),
+ .driver_info = (unsigned long) &moschip_info,
+ },
+ {
USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID),
.driver_info = (unsigned long) &moschip_info,
},
if (!(rcv->flags & IFF_UP))
goto tx_drop;
- if (dev->features & NETIF_F_NO_CSUM)
+ /* don't change ip_summed == CHECKSUM_PARTIAL, as that
+ will cause bad checksum on forwarded packets */
+ if (skb->ip_summed == CHECKSUM_NONE)
skb->ip_summed = rcv_priv->ip_summed;
length = skb->len + ETH_HLEN;
SET_ETHTOOL_OPS(dev, &prism2_ethtool_ops);
- netif_stop_queue(dev);
}
static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
.mod_params = &iwlagn_mod_params,
.base_params = &iwl1000_base_params,
.ht_params = &iwl1000_ht_params,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl100_bg_cfg = {
.ops = &iwl1000_ops,
.mod_params = &iwlagn_mod_params,
.base_params = &iwl1000_base_params,
+ .use_new_eeprom_reading = true,
};
MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
.ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
.need_temp_offset_calib = true,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl6000g2a_2abg_cfg = {
.base_params = &iwl6000_base_params,
.need_dc_calib = true,
.need_temp_offset_calib = true,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl6000g2a_2bg_cfg = {
.base_params = &iwl6000_base_params,
.need_dc_calib = true,
.need_temp_offset_calib = true,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl6000g2b_2agn_cfg = {
.need_temp_offset_calib = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl6000g2b_2abg_cfg = {
.need_temp_offset_calib = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl6000g2b_2bgn_cfg = {
.need_temp_offset_calib = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl6000g2b_2bg_cfg = {
.need_temp_offset_calib = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl6000g2b_bgn_cfg = {
.need_temp_offset_calib = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl6000g2b_bg_cfg = {
.need_temp_offset_calib = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+ .use_new_eeprom_reading = true,
};
/*
.base_params = &iwl6050_base_params,
.ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl6050_2abg_cfg = {
.need_dc_calib = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+ .use_new_eeprom_reading = true,
};
struct iwl_cfg iwl130_bg_cfg = {
.need_dc_calib = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+ .use_new_eeprom_reading = true,
};
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
/**
* iwlcore_eeprom_enhanced_txpower: process enhanced tx power info
*/
-void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
+static void iwlcore_eeprom_enhanced_txpower_old(struct iwl_priv *priv)
{
int eeprom_section_count = 0;
int section, element;
* always check for valid entry before process
* the information
*/
- if (!enhanced_txpower->common || enhanced_txpower->reserved)
+ if (!(enhanced_txpower->flags || enhanced_txpower->channel) ||
+ enhanced_txpower->delta_20_in_40)
continue;
for (element = 0; element < eeprom_section_count; element++) {
}
}
}
+
+static void
+iwlcore_eeprom_enh_txp_read_element(struct iwl_priv *priv,
+ struct iwl_eeprom_enhanced_txpwr *txp,
+ s8 max_txpower_avg)
+{
+ int ch_idx;
+ bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ;
+ enum ieee80211_band band;
+
+ band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
+ IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
+
+ for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) {
+ struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx];
+
+ /* update matching channel or from common data only */
+ if (txp->channel != 0 && ch_info->channel != txp->channel)
+ continue;
+
+ /* update matching band only */
+ if (band != ch_info->band)
+ continue;
+
+ if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) {
+ ch_info->max_power_avg = max_txpower_avg;
+ ch_info->curr_txpow = max_txpower_avg;
+ ch_info->scan_power = max_txpower_avg;
+ }
+
+ if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg)
+ ch_info->ht40_max_power_avg = max_txpower_avg;
+ }
+}
+
+#define EEPROM_TXP_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
+#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
+#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
+
+static void iwlcore_eeprom_enhanced_txpower_new(struct iwl_priv *priv)
+{
+ struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
+ int idx, entries;
+ __le16 *txp_len;
+ s8 max_txp_avg, max_txp_avg_halfdbm;
+
+ BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
+
+ /* the length is in 16-bit words, but we want entries */
+ txp_len = (__le16 *) iwlagn_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS);
+ entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
+
+ txp_array = (void *) iwlagn_eeprom_query_addr(priv, EEPROM_TXP_OFFS);
+ for (idx = 0; idx < entries; idx++) {
+ txp = &txp_array[idx];
+
+ /* skip invalid entries */
+ if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
+ continue;
+
+ max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
+ &max_txp_avg_halfdbm);
+
+ /*
+ * Update the user limit values values to the highest
+ * power supported by any channel
+ */
+ if (max_txp_avg > priv->tx_power_user_lmt)
+ priv->tx_power_user_lmt = max_txp_avg;
+ if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm)
+ priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm;
+
+ iwlcore_eeprom_enh_txp_read_element(priv, txp, max_txp_avg);
+ }
+}
+
+void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
+{
+ if (priv->cfg->use_new_eeprom_reading)
+ iwlcore_eeprom_enhanced_txpower_new(priv);
+ else
+ iwlcore_eeprom_enhanced_txpower_old(priv);
+}
case INDIRECT_REGULATORY:
offset = iwl_eeprom_query16(priv, EEPROM_LINK_REGULATORY);
break;
+ case INDIRECT_TXP_LIMIT:
+ offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT);
+ break;
+ case INDIRECT_TXP_LIMIT_SIZE:
+ offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT_SIZE);
+ break;
case INDIRECT_CALIBRATION:
offset = iwl_eeprom_query16(priv, EEPROM_LINK_CALIBRATION);
break;
const bool need_temp_offset_calib; /* if used set to true */
u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
+ const bool use_new_eeprom_reading; /* temporary, remove later */
};
/***************************
s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
} __packed;
+enum iwl_eeprom_enhanced_txpwr_flags {
+ IWL_EEPROM_ENH_TXP_FL_VALID = BIT(0),
+ IWL_EEPROM_ENH_TXP_FL_BAND_52G = BIT(1),
+ IWL_EEPROM_ENH_TXP_FL_OFDM = BIT(2),
+ IWL_EEPROM_ENH_TXP_FL_40MHZ = BIT(3),
+ IWL_EEPROM_ENH_TXP_FL_HT_AP = BIT(4),
+ IWL_EEPROM_ENH_TXP_FL_RES1 = BIT(5),
+ IWL_EEPROM_ENH_TXP_FL_RES2 = BIT(6),
+ IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE = BIT(7),
+};
+
/**
* iwl_eeprom_enhanced_txpwr structure
* This structure presents the enhanced regulatory tx power limit layout
* Enhanced regulatory tx power portion of eeprom image can be broken down
* into individual structures; each one is 8 bytes in size and contain the
* following information
- * @common: (desc + channel) not used by driver, should _NOT_ be "zero"
+ * @flags: entry flags
+ * @channel: channel number
* @chain_a_max_pwr: chain a max power in 1/2 dBm
* @chain_b_max_pwr: chain b max power in 1/2 dBm
* @chain_c_max_pwr: chain c max power in 1/2 dBm
- * @reserved: not used, should be "zero"
+ * @delta_20_in_40: 20-in-40 deltas (hi/lo)
* @mimo2_max_pwr: mimo2 max power in 1/2 dBm
* @mimo3_max_pwr: mimo3 max power in 1/2 dBm
*
*/
struct iwl_eeprom_enhanced_txpwr {
- __le16 common;
+ u8 flags;
+ u8 channel;
s8 chain_a_max;
s8 chain_b_max;
s8 chain_c_max;
- s8 reserved;
+ u8 delta_20_in_40;
s8 mimo2_max;
s8 mimo3_max;
} __packed;
#define EEPROM_LINK_CALIBRATION (2*0x67)
#define EEPROM_LINK_PROCESS_ADJST (2*0x68)
#define EEPROM_LINK_OTHERS (2*0x69)
+#define EEPROM_LINK_TXP_LIMIT (2*0x6a)
+#define EEPROM_LINK_TXP_LIMIT_SIZE (2*0x6b)
/* agn regulatory - indirect access */
#define EEPROM_REG_BAND_1_CHANNELS ((0x08)\
#define INDIRECT_CALIBRATION 0x00040000
#define INDIRECT_PROCESS_ADJST 0x00050000
#define INDIRECT_OTHERS 0x00060000
+#define INDIRECT_TXP_LIMIT 0x00070000
+#define INDIRECT_TXP_LIMIT_SIZE 0x00080000
#define INDIRECT_ADDRESS 0x00100000
/* General */
print_ssid(ssid_buf, ssid, ssid_len),
LBS_SCAN_RSSI_TO_MBM(rssi)/100);
- if (channel ||
+ if (channel &&
!(channel->flags & IEEE80211_CHAN_DISABLED))
cfg80211_inform_bss(wiphy, channel,
bssid, le64_to_cpu(*(__le64 *)tsfdesc),
static struct usb_device_id p54u_table[] __devinitdata = {
/* Version 1 devices (pci chip + net2280) */
+ {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */
{USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */
{USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
{USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */
{USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
{USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
{USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
+ {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */
{USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */
{USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
+ {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */
+ {USB_DEVICE(0x15a9, 0x0002)}, /* Gemtek WUBI-100GW 802.11g */
{USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */
+ {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */
{USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
{USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
{USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
{USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
{USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */
{USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
+ {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */
{USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
{USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
{USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
DRIVER_REQUIRE_COPY_IV,
DRIVER_REQUIRE_L2PAD,
DRIVER_REQUIRE_TXSTATUS_FIFO,
+ DRIVER_REQUIRE_TASKLET_CONTEXT,
/*
* Driver features
* through a mac80211 library call (RTS/CTS) then we should not
* send the status report back.
*/
- if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
- ieee80211_tx_status(rt2x00dev->hw, entry->skb);
- else
+ if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) {
+ if (test_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags))
+ ieee80211_tx_status(rt2x00dev->hw, entry->skb);
+ else
+ ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb);
+ } else
dev_kfree_skb_any(entry->skb);
/*
}
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz + 2);
yp->rx_skbuff[i] = skb;
if (skb == NULL)
break;
for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) {
entry = yp->dirty_rx % RX_RING_SIZE;
if (yp->rx_skbuff[entry] == NULL) {
- struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz + 2);
if (skb == NULL)
break; /* Better luck next round. */
yp->rx_skbuff[entry] = skb;
info.of_node = of_node_get(node);
info.archdata = &dev_ad;
- request_module("%s", info.type);
+ request_module("%s%s", I2C_MODULE_PREFIX, info.type);
result = i2c_new_device(adap, &info);
if (result == NULL) {
}
}
-static bool pci_bus_resource_better(struct resource *res1, bool pos1,
- struct resource *res2, bool pos2)
-{
- /* If exactly one is positive decode, always prefer that one */
- if (pos1 != pos2)
- return pos1 ? true : false;
-
- /* Prefer the one that contains the highest address */
- if (res1->end != res2->end)
- return (res1->end > res2->end) ? true : false;
-
- /* Otherwise, prefer the one with highest "center of gravity" */
- if (res1->start != res2->start)
- return (res1->start > res2->start) ? true : false;
-
- /* Otherwise, choose one arbitrarily (but consistently) */
- return (res1 > res2) ? true : false;
-}
-
-static bool pci_bus_resource_positive(struct pci_bus *bus, struct resource *res)
-{
- struct pci_bus_resource *bus_res;
-
- /*
- * This relies on the fact that pci_bus.resource[] refers to P2P or
- * CardBus bridge base/limit registers, which are always positively
- * decoded. The pci_bus.resources list contains host bridge or
- * subtractively decoded resources.
- */
- list_for_each_entry(bus_res, &bus->resources, list) {
- if (bus_res->res == res)
- return (bus_res->flags & PCI_SUBTRACTIVE_DECODE) ?
- false : true;
- }
- return true;
-}
-
-/*
- * Find the next-best bus resource after the cursor "res". If the cursor is
- * NULL, return the best resource. "Best" means that we prefer positive
- * decode regions over subtractive decode, then those at higher addresses.
- */
-static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus,
- unsigned int type,
- struct resource *res)
-{
- bool res_pos, r_pos, prev_pos = false;
- struct resource *r, *prev = NULL;
- int i;
-
- res_pos = pci_bus_resource_positive(bus, res);
- pci_bus_for_each_resource(bus, r, i) {
- if (!r)
- continue;
-
- if ((r->flags & IORESOURCE_TYPE_BITS) != type)
- continue;
-
- r_pos = pci_bus_resource_positive(bus, r);
- if (!res || pci_bus_resource_better(res, res_pos, r, r_pos)) {
- if (!prev || pci_bus_resource_better(r, r_pos,
- prev, prev_pos)) {
- prev = r;
- prev_pos = r_pos;
- }
- }
- }
-
- return prev;
-}
-
/**
* pci_bus_alloc_resource - allocate a resource from a parent bus
* @bus: PCI bus
resource_size_t),
void *alignf_data)
{
- int ret = -ENOMEM;
+ int i, ret = -ENOMEM;
struct resource *r;
resource_size_t max = -1;
- unsigned int type = res->flags & IORESOURCE_TYPE_BITS;
type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
if (!(res->flags & IORESOURCE_MEM_64))
max = PCIBIOS_MAX_MEM_32;
- /* Look for space at highest addresses first */
- r = pci_bus_find_resource_prev(bus, type, NULL);
- for ( ; r; r = pci_bus_find_resource_prev(bus, type, r)) {
+ pci_bus_for_each_resource(bus, r, i) {
+ if (!r)
+ continue;
+
/* type_mask must match */
if ((res->flags ^ r->flags) & type_mask)
continue;
(unsigned long long)drhd->reg_base_addr, ret);
return -1;
}
+
+ /*
+ * Clear any previous faults.
+ */
+ dmar_fault(iommu->irq, iommu);
}
return 0;
static int __init select_detection_mode(void)
{
struct dummy_slot *slot, *tmp;
- pcie_port_service_register(&dummy_driver);
+ if (pcie_port_service_register(&dummy_driver))
+ return PCIEHP_DETECT_ACPI;
pcie_port_service_unregister(&dummy_driver);
list_for_each_entry_safe(slot, tmp, &dummy_slots, list) {
list_del(&slot->list);
{
u32 cfg;
+ if (!pci_find_capability(dev, PCI_CAP_ID_HT))
+ return;
+
pci_read_config_dword(dev, 0x74, &cfg);
if (cfg & ((1 << 2) | (1 << 15))) {
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
#endif /*CONFIG_MMC_RICOH_MMC*/
+#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
+#define VTUNCERRMSK_REG 0x1ac
+#define VTD_MSK_SPEC_ERRORS (1 << 31)
+/*
+ * This is a quirk for masking vt-d spec defined errors to platform error
+ * handling logic. With out this, platforms using Intel 7500, 5500 chipsets
+ * (and the derivative chipsets like X58 etc) seem to generate NMI/SMI (based
+ * on the RAS config settings of the platform) when a vt-d fault happens.
+ * The resulting SMI caused the system to hang.
+ *
+ * VT-d spec related errors are already handled by the VT-d OS code, so no
+ * need to report the same error through other channels.
+ */
+static void vtd_mask_spec_errors(struct pci_dev *dev)
+{
+ u32 word;
+
+ pci_read_config_dword(dev, VTUNCERRMSK_REG, &word);
+ pci_write_config_dword(dev, VTUNCERRMSK_REG, word | VTD_MSK_SPEC_ERRORS);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, vtd_mask_spec_errors);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors);
+#endif
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
struct pci_fixup *end)
#include <drm/i915_drm.h>
#include <asm/msr.h>
#include <asm/processor.h>
+#include "intel_ips.h"
#define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32
#define thm_writel(off, val) writel((val), ips->regmap + (off))
static const int IPS_ADJUST_PERIOD = 5000; /* ms */
+static bool late_i915_load = false;
/* For initial average collection */
static const int IPS_SAMPLE_PERIOD = 200; /* ms */
u64 orig_turbo_ratios;
};
+static bool
+ips_gpu_turbo_enabled(struct ips_driver *ips);
+
/**
* ips_cpu_busy - is CPU busy?
* @ips: IPS driver struct
*/
static bool ips_gpu_busy(struct ips_driver *ips)
{
- if (!ips->gpu_turbo_enabled)
+ if (!ips_gpu_turbo_enabled(ips))
return false;
return ips->gpu_busy();
*/
static void ips_gpu_raise(struct ips_driver *ips)
{
- if (!ips->gpu_turbo_enabled)
+ if (!ips_gpu_turbo_enabled(ips))
return;
if (!ips->gpu_raise())
*/
static void ips_gpu_lower(struct ips_driver *ips)
{
- if (!ips->gpu_turbo_enabled)
+ if (!ips_gpu_turbo_enabled(ips))
return;
if (!ips->gpu_lower())
return false;
}
+static bool
+ips_gpu_turbo_enabled(struct ips_driver *ips)
+{
+ if (!ips->gpu_busy && late_i915_load) {
+ if (ips_get_i915_syms(ips)) {
+ dev_info(&ips->dev->dev,
+ "i915 driver attached, reenabling gpu turbo\n");
+ ips->gpu_turbo_enabled = !(thm_readl(THM_HTS) & HTS_GTD_DIS);
+ }
+ }
+
+ return ips->gpu_turbo_enabled;
+}
+
+void
+ips_link_to_i915_driver()
+{
+ /* We can't cleanly get at the various ips_driver structs from
+ * this caller (the i915 driver), so just set a flag saying
+ * that it's time to try getting the symbols again.
+ */
+ late_i915_load = true;
+}
+EXPORT_SYMBOL_GPL(ips_link_to_i915_driver);
+
static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), },
--- /dev/null
+/*
+ * Copyright (c) 2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
+void ips_link_to_i915_driver(void);
static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct rs5c372 *rs5c = i2c_get_clientdata(client);
- unsigned char buf[8];
+ unsigned char buf[7];
int addr;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
bfa_trc(fabric->fcs, event);
wwn2str(pwwn_ptr, fabric->bport.port_cfg.pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Port is isolated due to VF_ID mismatch. "
"PWWN: %s Port VF_ID: %04x switch port VF_ID: %04x.",
pwwn_ptr, fabric->fcs->port_vfid,
wwn2str(pwwn_ptr, bfa_fcs_lport_get_pwwn(&fabric->bport));
wwn2str(fwwn_ptr,
bfa_fcs_lport_get_fabric_name(&fabric->bport));
- BFA_LOG(KERN_WARNING, bfad, log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Base port WWN = %s Fabric WWN = %s\n",
pwwn_ptr, fwwn_ptr);
}
bfa_fcb_itnim_online(itnim->itnim_drv);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
wwn2str(rpwwn_buf, itnim->rport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Target (WWN = %s) is online for initiator (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
break;
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
wwn2str(rpwwn_buf, itnim->rport->pwwn);
if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE)
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Target (WWN = %s) connectivity lost for "
"initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
else
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Target (WWN = %s) offlined by initiator (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
break;
__port_action[port->fabric->fab_type].online(port);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Logical port online: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE)
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Logical port lost fabric connectivity: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
else
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Logical port taken offline: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
char lpwwn_buf[BFA_STRING_32];
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Logical port deleted: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
vport ? vport->vport_drv : NULL);
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(lport));
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"New logical port created: WWN = %s Role = %s\n",
lpwwn_buf, "Initiator");
wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
wwn2str(rpwwn_buf, rport->pwwn);
if (!BFA_FCS_PID_IS_WKA(rport->pid))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Remote port (WWN = %s) online for logical port (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
}
wwn2str(rpwwn_buf, rport->pwwn);
if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
if (bfa_fcs_lport_is_online(rport->port) == BFA_TRUE)
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Remote port (WWN = %s) connectivity lost for "
"logical port (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
else
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Remote port (WWN = %s) offlined by "
"logical port (WWN = %s)\n",
rpwwn_buf, lpwwn_buf);
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
bfa_ioc_hb_monitor(ioc);
- BFA_LOG(KERN_INFO, bfad, log_level, "IOC enabled\n");
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n");
}
static void
{
struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
bfa_iocpf_disable(ioc);
- BFA_LOG(KERN_INFO, bfad, log_level, "IOC disabled\n");
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC disabled\n");
}
/*
notify->cbfn(notify->cbarg);
}
- BFA_LOG(KERN_CRIT, bfad, log_level,
+ BFA_LOG(KERN_CRIT, bfad, bfa_log_level,
"Heart Beat of IOC has failed\n");
}
* Provide enable completion callback.
*/
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
- BFA_LOG(KERN_WARNING, bfad, log_level,
+ BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
"Running firmware version is incompatible "
"with the driver version\n");
}
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE);
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port online: WWN = %s\n", pwwn_buf);
break;
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port disabled: WWN = %s\n", pwwn_buf);
break;
BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
wwn2str(pwwn_buf, fcport->pwwn);
if (BFA_PORT_IS_DISABLED(fcport->bfa))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
else
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Base port (WWN = %s) "
"lost fabric connectivity\n", pwwn_buf);
break;
bfa_fcport_reset_linkinfo(fcport);
wwn2str(pwwn_buf, fcport->pwwn);
if (BFA_PORT_IS_DISABLED(fcport->bfa))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
else
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Base port (WWN = %s) "
"lost fabric connectivity\n", pwwn_buf);
break;
bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE);
wwn2str(pwwn_buf, fcport->pwwn);
if (BFA_PORT_IS_DISABLED(fcport->bfa))
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port offline: WWN = %s\n", pwwn_buf);
else
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"Base port (WWN = %s) "
"lost fabric connectivity\n", pwwn_buf);
break;
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port enabled: WWN = %s\n", pwwn_buf);
break;
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
wwn2str(pwwn_buf, fcport->pwwn);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"Base port enabled: WWN = %s\n", pwwn_buf);
break;
int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT;
int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH;
int bfa_io_max_sge = BFAD_IO_MAX_SGE;
-int log_level = 3; /* WARNING log level */
+int bfa_log_level = 3; /* WARNING log level */
int ioc_auto_recover = BFA_TRUE;
int bfa_linkup_delay = -1;
int fdmi_enable = BFA_TRUE;
MODULE_PARM_DESC(bfa_lun_queue_depth, "Lun queue depth, default=32, Range[>0]");
module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(bfa_io_max_sge, "Max io scatter/gather elements, default=255");
-module_param(log_level, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(log_level, "Driver log level, default=3, "
+module_param(bfa_log_level, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_log_level, "Driver log level, default=3, "
"Range[Critical:1|Error:2|Warning:3|Info:4]");
module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ioc_auto_recover, "IOC auto recovery, default=1, "
} else
bfad_os_rport_online_wait(bfad);
- BFA_LOG(KERN_INFO, bfad, log_level, "bfa device claimed\n");
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "bfa device claimed\n");
return BFA_STATUS_OK;
}
extern int rport_del_timeout;
extern int bfa_lun_queue_depth;
extern int bfa_io_max_sge;
-extern int log_level;
+extern int bfa_log_level;
extern int ioc_auto_recover;
extern int bfa_linkup_delay;
extern int msix_disable_cb;
}
bfa_trc(bfad, hal_io->iotag);
- BFA_LOG(KERN_INFO, bfad, log_level, "scsi%d: abort cmnd %p iotag %x\n",
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
+ "scsi%d: abort cmnd %p iotag %x\n",
im_port->shost->host_no, cmnd, hal_io->iotag);
(void) bfa_ioim_abort(hal_io);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
cmnd->scsi_done(cmnd);
bfa_trc(bfad, hal_io->iotag);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"scsi%d: complete abort 0x%p iotag 0x%x\n",
im_port->shost->host_no, cmnd, hal_io->iotag);
return SUCCESS;
tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
if (!tskim) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"target reset, fail to allocate tskim\n");
rc = BFA_STATUS_FAILED;
goto out;
tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
if (!tskim) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"LUN reset, fail to allocate tskim");
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
rc = FAILED;
task_status = cmnd->SCp.Status >> 1;
if (task_status != BFI_TSKIM_STS_OK) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"LUN reset failure, status: %d\n", task_status);
rc = FAILED;
}
task_status = cmnd->SCp.Status >> 1;
if (task_status != BFI_TSKIM_STS_OK) {
- BFA_LOG(KERN_ERR, bfad, log_level,
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
"target reset failure,"
" status: %d\n", task_status);
err_cnt++;
fcid = bfa_fcs_itnim_get_fcid(&itnim_drv->fcs_itnim);
wwn2str(wwpn_str, wwpn);
fcid2str(fcid_str, fcid);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"ITNIM FREE scsi%d: FCID: %s WWPN: %s\n",
port->im_port->shost->host_no,
fcid_str, wwpn_str);
bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
{
bfa_trc(bfad, bfad->inst_no);
- BFA_LOG(KERN_INFO, bfad, log_level, "Free scsi%d\n",
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Free scsi%d\n",
im_port->shost->host_no);
fc_remove_host(im_port->shost);
fcid2str(fcid_str, fcid);
list_add_tail(&itnim->list_entry,
&im_port->itnim_mapped_list);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"ITNIM ONLINE Target: %d:0:%d "
"FCID: %s WWPN: %s\n",
im_port->shost->host_no,
wwn2str(wwpn_str, wwpn);
fcid2str(fcid_str, fcid);
list_del(&itnim->list_entry);
- BFA_LOG(KERN_INFO, bfad, log_level,
+ BFA_LOG(KERN_INFO, bfad, bfa_log_level,
"ITNIM OFFLINE Target: %d:0:%d "
"FCID: %s WWPN: %s\n",
im_port->shost->host_no,
blk_queue_max_segment_size(q, dma_get_max_seg_size(dev));
- /* New queue, no concurrency on queue_flags */
if (!shost->use_clustering)
- queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
+ q->limits.cluster = 0;
/*
* set a reasonable default alignment on word boundaries: the
list_add_tail(&d->list, &intc_list);
raw_spin_lock_init(&d->lock);
+ INIT_RADIX_TREE(&d->tree, GFP_ATOMIC);
d->index = nr_intc_controllers;
msg = container_of(mcfqspi->msgq.next, struct spi_message,
queue);
- list_del_init(&mcfqspi->msgq);
+ list_del_init(&msg->queue);
spin_unlock_irqrestore(&mcfqspi->lock, flags);
spi = msg->spi;
.of_match_table = mpc52xx_spi_match,
},
.probe = mpc52xx_spi_probe,
- .remove = __exit_p(mpc52xx_spi_remove),
+ .remove = __devexit_p(mpc52xx_spi_remove),
};
static int __init mpc52xx_spi_init(void)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:omap2_mcspi");
+#ifdef CONFIG_SUSPEND
+/*
+ * When SPI wake up from off-mode, CS is in activate state. If it was in
+ * unactive state when driver was suspend, then force it to unactive state at
+ * wake up.
+ */
+static int omap2_mcspi_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct omap2_mcspi_cs *cs;
+
+ omap2_mcspi_enable_clocks(mcspi);
+ list_for_each_entry(cs, &omap2_mcspi_ctx[master->bus_num - 1].cs,
+ node) {
+ if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
+
+ /*
+ * We need to toggle CS state for OMAP take this
+ * change in account.
+ */
+ MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 1);
+ __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
+ MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 0);
+ __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
+ }
+ }
+ omap2_mcspi_disable_clocks(mcspi);
+ return 0;
+}
+#else
+#define omap2_mcspi_resume NULL
+#endif
+
+static const struct dev_pm_ops omap2_mcspi_pm_ops = {
+ .resume = omap2_mcspi_resume,
+};
+
static struct platform_driver omap2_mcspi_driver = {
.driver = {
.name = "omap2_mcspi",
.owner = THIS_MODULE,
+ .pm = &omap2_mcspi_pm_ops
},
.remove = __exit_p(omap2_mcspi_remove),
};
list_del(&master->list);
mutex_unlock(&board_lock);
- dummy = device_for_each_child(master->dev.parent, &master->dev,
- __unregister);
+ dummy = device_for_each_child(&master->dev, NULL, __unregister);
device_unregister(&master->dev);
}
EXPORT_SYMBOL_GPL(spi_unregister_master);
return mpc8xxx_spi->count;
}
-static void fsl_espi_addr2cmd(unsigned int addr, u8 *cmd)
+static inline void fsl_espi_addr2cmd(unsigned int addr, u8 *cmd)
{
- if (cmd[1] && cmd[2] && cmd[3]) {
+ if (cmd) {
cmd[1] = (u8)(addr >> 16);
cmd[2] = (u8)(addr >> 8);
cmd[3] = (u8)(addr >> 0);
}
}
-static unsigned int fsl_espi_cmd2addr(u8 *cmd)
+static inline unsigned int fsl_espi_cmd2addr(u8 *cmd)
{
- if (cmd[1] && cmd[2] && cmd[3])
+ if (cmd)
return cmd[1] << 16 | cmd[2] << 8 | cmd[3] << 0;
return 0;
}
}
- addr = fsl_espi_cmd2addr(local_buf);
- addr += pos;
- fsl_espi_addr2cmd(addr, local_buf);
+ if (pos > 0) {
+ addr = fsl_espi_cmd2addr(local_buf);
+ addr += pos;
+ fsl_espi_addr2cmd(addr, local_buf);
+ }
espi_trans->n_tx = n_tx;
espi_trans->n_rx = trans_len;
/* We need handle RX first */
if (events & SPIE_NE) {
- u32 rx_data;
+ u32 rx_data, tmp;
+ u8 rx_data_8;
/* Spin until RX is done */
while (SPIE_RXCNT(events) < min(4, mspi->len)) {
cpu_relax();
events = mpc8xxx_spi_read_reg(®_base->event);
}
- mspi->len -= 4;
- rx_data = mpc8xxx_spi_read_reg(®_base->receive);
+ if (mspi->len >= 4) {
+ rx_data = mpc8xxx_spi_read_reg(®_base->receive);
+ } else {
+ tmp = mspi->len;
+ rx_data = 0;
+ while (tmp--) {
+ rx_data_8 = in_8((u8 *)®_base->receive);
+ rx_data |= (rx_data_8 << (tmp * 8));
+ }
+
+ rx_data <<= (4 - mspi->len) * 8;
+ }
+
+ mspi->len -= 4;
if (mspi->rx)
mspi->get_rx(rx_data, mspi);
return ARRAY_SIZE(formats);
}
-struct cx25821_fmt *format_by_fourcc(unsigned int fourcc)
+struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
{
unsigned int i;
pix_format =
(dev->channels[ch_id].pixel_formats ==
PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
+ fh->fmt = cx25821_format_by_fourcc(pix_format);
v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
if (0 != err)
return err;
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
fh->vidq.field = f->fmt.pix.field;
/* check if width and height is valid based on set standard */
enum v4l2_field field;
unsigned int maxw, maxh;
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
#define FORMAT_FLAGS_PACKED 0x01
extern struct cx25821_fmt formats[];
-extern struct cx25821_fmt *format_by_fourcc(unsigned int fourcc);
+extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc);
extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM];
extern void cx25821_dump_video_queue(struct cx25821_dev *dev,
int ret = 0;
struct zram *zram = queue->queuedata;
- if (unlikely(!zram->init_done)) {
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
- }
-
if (!valid_io_request(zram, bio)) {
zram_stat64_inc(zram, &zram->stats.invalid_io);
bio_io_error(bio);
if (msg->len < 128)
*--dp = (msg->len << 1) | EA;
else {
- *--dp = ((msg->len & 127) << 1) | EA;
- *--dp = (msg->len >> 6) & 0xfe;
+ *--dp = (msg->len >> 7); /* bits 7 - 15 */
+ *--dp = (msg->len & 127) << 1; /* bits 0 - 6 */
}
}
{
struct gsm_msg *msg;
msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
+ if (msg == NULL)
+ return;
msg->data[0] = (cmd & 0xFE) << 1 | EA; /* Clear C/R */
msg->data[1] = (dlen << 1) | EA;
memcpy(msg->data + 2, data, dlen);
goto err1;
}
- sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
- if (sc->kthread == ERR_PTR(-ENOMEM)) {
+ /* Create worker thread, but don't start it here. Start it after
+ * all usbatm generic initialization is done.
+ */
+ sc->kthread = kthread_create(uea_kthread, sc, "ueagle-atm");
+ if (IS_ERR(sc->kthread)) {
uea_err(INS_TO_USBDEV(sc), "failed to create thread\n");
goto err2;
}
static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *usb = interface_to_usbdev(intf);
+ int ret;
uea_enters(usb);
uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
if (UEA_IS_PREFIRM(id))
return uea_load_firmware(usb, UEA_CHIP_VERSION(id));
- return usbatm_usb_probe(intf, id, &uea_usbatm_driver);
+ ret = usbatm_usb_probe(intf, id, &uea_usbatm_driver);
+ if (ret == 0) {
+ struct usbatm_data *usbatm = usb_get_intfdata(intf);
+ struct uea_softc *sc = usbatm->driver_data;
+
+ /* Ensure carrier is initialized to off as early as possible */
+ UPDATE_ATM_SIGNAL(ATM_PHY_SIG_LOST);
+
+ /* Only start the worker thread when all init is done */
+ wake_up_process(sc->kthread);
+ }
+
+ return ret;
}
static void uea_disconnect(struct usb_interface *intf)
If you are unsure about this, say N here.
config USB_OTG
- bool
+ bool "OTG support"
depends on USB && EXPERIMENTAL
depends on USB_SUSPEND
default n
-
+ help
+ The most notable feature of USB OTG is support for a
+ "Dual-Role" device, which can act as either a device
+ or a host. The initial role is decided by the type of
+ plug inserted and can be changed later when two dual
+ role devices talk to each other.
+
+ Select this only if your board has Mini-AB/Micro-AB
+ connector.
config USB_OTG_WHITELIST
bool "Rely on OTG Targeted Peripherals List"
kfree(cdev->req->buf);
usb_ep_free_request(gadget->ep0, cdev->req);
}
+ device_remove_file(&gadget->dev, &dev_attr_suspended);
kfree(cdev);
set_gadget_data(gadget, NULL);
- device_remove_file(&gadget->dev, &dev_attr_suspended);
composite = NULL;
}
*/
usb_ep_autoconfig_reset(cdev->gadget);
- /* standardized runtime overrides for device ID data */
- if (idVendor)
- cdev->desc.idVendor = cpu_to_le16(idVendor);
- if (idProduct)
- cdev->desc.idProduct = cpu_to_le16(idProduct);
- if (bcdDevice)
- cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
-
/* composite gadget needs to assign strings for whole device (like
* serial number), register function drivers, potentially update
* power state and consumption, etc
cdev->desc = *composite->dev;
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+ /* standardized runtime overrides for device ID data */
+ if (idVendor)
+ cdev->desc.idVendor = cpu_to_le16(idVendor);
+ if (idProduct)
+ cdev->desc.idProduct = cpu_to_le16(idProduct);
+ if (bcdDevice)
+ cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
+
/* stirng overrides */
if (iManufacturer || !cdev->desc.iManufacturer) {
if (!iManufacturer && !composite->iManufacturer &&
xhci->port_array[i] = (u8) -1;
}
/* FIXME: Should we disable the port? */
+ continue;
}
xhci->port_array[i] = major_revision;
if (major_revision == 0x03)
return -ENOMEM;
port_index = 0;
- for (i = 0; i < num_ports; i++)
- if (xhci->port_array[i] != 0x03) {
- xhci->usb2_ports[port_index] =
- &xhci->op_regs->port_status_base +
- NUM_PORT_REGS*i;
- xhci_dbg(xhci, "USB 2.0 port at index %u, "
- "addr = %p\n", i,
- xhci->usb2_ports[port_index]);
- port_index++;
- }
+ for (i = 0; i < num_ports; i++) {
+ if (xhci->port_array[i] == 0x03 ||
+ xhci->port_array[i] == 0 ||
+ xhci->port_array[i] == -1)
+ continue;
+
+ xhci->usb2_ports[port_index] =
+ &xhci->op_regs->port_status_base +
+ NUM_PORT_REGS*i;
+ xhci_dbg(xhci, "USB 2.0 port at index %u, "
+ "addr = %p\n", i,
+ xhci->usb2_ports[port_index]);
+ port_index++;
+ }
}
if (xhci->num_usb3_ports) {
xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)*
/*
* uss720.c -- USS720 USB Parport Cable.
*
- * Copyright (C) 1999, 2005
+ * Copyright (C) 1999, 2005, 2010
* Thomas Sailer (t.sailer@alumni.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
{ USB_DEVICE(0x0557, 0x2001) },
{ USB_DEVICE(0x0729, 0x1284) },
{ USB_DEVICE(0x1293, 0x0002) },
+ { USB_DEVICE(0x1293, 0x0002) },
+ { USB_DEVICE(0x050d, 0x0002) },
{ } /* Terminating entry */
};
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ }, /* Optional parameter entry */
#define MJSG_HD_RADIO_PID 0x937C
/*
+ * D.O.Tec products (http://www.directout.eu)
+ */
+#define FTDI_DOTEC_PID 0x9868
+
+/*
* Xverve Signalyzer tools (http://www.signalyzer.com/)
*/
#define XVERVE_SIGNALYZER_ST_PID 0xBCA0
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_MAX_SECTORS_64),
+/* Reported by Vitaly Kuznetsov <vitty@altlinux.ru> */
+UNUSUAL_DEV( 0x04e8, 0x5122, 0x0000, 0x9999,
+ "Samsung",
+ "YP-CP3",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 | US_FL_BULK_IGNORE_TAG),
+
/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
* Device uses standards-violating 32-byte Bulk Command Block Wrappers and
* reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011.
backlight_device_unregister(crp->cr_backlight_device);
lcd_device_unregister(crp->cr_lcd_device);
pci_dev_put(lpc_dev);
+ kfree(crp);
return 0;
}
if (gen->base == hw->base)
return true;
/* is the generic aperture base inside the hw base->hw base+size */
- if (gen->base > hw->base && gen->base <= hw->base + hw->size)
+ if (gen->base > hw->base && gen->base < hw->base + hw->size)
return true;
return false;
}
#define LCDC_SIZE 0x04
#define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20)
-#ifdef CONFIG_ARCH_MX1
-#define SIZE_YMAX(y) ((y) & 0x1ff)
-#else
-#define SIZE_YMAX(y) ((y) & 0x3ff)
-#endif
+#define YMAX_MASK (cpu_is_mx1() ? 0x1ff : 0x3ff)
+#define SIZE_YMAX(y) ((y) & YMAX_MASK)
#define LCDC_VPW 0x08
#define VPW_VPW(x) ((x) & 0x3ff)
if (var->right_margin > 255)
printk(KERN_ERR "%s: invalid right_margin %d\n",
info->fix.id, var->right_margin);
- if (var->yres < 1 || var->yres > 511)
+ if (var->yres < 1 || var->yres > YMAX_MASK)
printk(KERN_ERR "%s: invalid yres %d\n",
info->fix.id, var->yres);
if (var->vsync_len > 100)
config FB_OMAP
tristate "OMAP frame buffer support (EXPERIMENTAL)"
- depends on FB && ARCH_OMAP && (OMAP2_DSS = "n")
-
+ depends on FB && (OMAP2_DSS = "n")
+ depends on ARCH_OMAP1 || ARCH_OMAP2 || ARCH_OMAP3
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
if (!size)
return;
- size = PAGE_ALIGN(size);
+ size = ALIGN(size, SZ_2M);
if (paddr) {
if (paddr & ~PAGE_MASK) {
return;
}
} else {
- paddr = memblock_alloc(size, PAGE_SIZE);
+ paddr = memblock_alloc(size, SZ_2M);
}
memblock_free(paddr, size);
found_rate_error = rate_error;
}
+ hdmi->var.width = hdmi->monspec.max_x * 10;
+ hdmi->var.height = hdmi->monspec.max_y * 10;
+
/*
* TODO 1: if no ->info is present, postpone running the config until
* after ->info first gets registered.
dev_dbg(info->dev, "Old %ux%u, new %ux%u\n",
mode1.xres, mode1.yres, mode2.xres, mode2.yres);
- if (fb_mode_is_equal(&mode1, &mode2))
+ if (fb_mode_is_equal(&mode1, &mode2)) {
+ /* It can be a different monitor with an equal video-mode */
+ old_var->width = new_var->width;
+ old_var->height = new_var->height;
return false;
+ }
dev_dbg(info->dev, "Switching %u -> %u lines\n",
mode1.yres, mode2.yres);
* on, if we run a resume here, the logo disappears
*/
if (lock_fb_info(hdmi->info)) {
- sh_hdmi_display_on(hdmi, hdmi->info);
- unlock_fb_info(hdmi->info);
+ struct fb_info *info = hdmi->info;
+ info->var.width = hdmi->var.width;
+ info->var.height = hdmi->var.height;
+ sh_hdmi_display_on(hdmi, info);
+ unlock_fb_info(info);
}
} else {
/* New monitor or have to wake up */
};
#define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs)
-#define DEFAULT_XRES 1280
-#define DEFAULT_YRES 1024
+#define MAX_XRES 1920
+#define MAX_YRES 1080
static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
[LDDCKPAT1R] = 0x400,
{
struct sh_mobile_lcdc_chan *ch = info->par;
- if (var->xres < 160 || var->xres > 1920 ||
- var->yres < 120 || var->yres > 1080 ||
- var->left_margin < 32 || var->left_margin > 320 ||
- var->right_margin < 12 || var->right_margin > 240 ||
- var->upper_margin < 12 || var->upper_margin > 120 ||
- var->lower_margin < 1 || var->lower_margin > 64 ||
- var->hsync_len < 32 || var->hsync_len > 240 ||
- var->vsync_len < 2 || var->vsync_len > 64 ||
- var->pixclock < 6000 || var->pixclock > 40000 ||
+ if (var->xres > MAX_XRES || var->yres > MAX_YRES ||
var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) {
- dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n",
- var->xres, var->yres,
- var->left_margin, var->right_margin,
- var->upper_margin, var->lower_margin,
- var->hsync_len, var->vsync_len,
- var->pixclock);
+ dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %ukHz!\n",
+ var->left_margin, var->xres, var->right_margin, var->hsync_len,
+ var->upper_margin, var->yres, var->lower_margin, var->vsync_len,
+ PICOS2KHZ(var->pixclock));
return -EINVAL;
}
return 0;
}
if (!mode)
- max_size = DEFAULT_XRES * DEFAULT_YRES;
+ max_size = MAX_XRES * MAX_YRES;
else if (max_cfg)
dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n",
max_cfg->xres, max_cfg->yres);
mode = &default_720p;
num_cfg = 1;
} else {
- num_cfg = ch->cfg.num_cfg;
+ num_cfg = cfg->num_cfg;
}
fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
fb_videomode_to_var(var, mode);
+ var->width = cfg->lcd_size_cfg.width;
+ var->height = cfg->lcd_size_cfg.height;
/* Default Y virtual resolution is 2x panel size */
var->yres_virtual = var->yres * 2;
var->activate = FB_ACTIVATE_NOW;
struct resource *r;
struct rdc321x_wdt_pdata *pdata;
- pdata = pdev->dev.platform_data;
+ pdata = platform_get_drvdata(pdev);
if (!pdata) {
dev_err(&pdev->dev, "no platform data supplied\n");
return -ENODEV;
static struct dentry *btrfs_get_parent(struct dentry *child)
{
struct inode *dir = child->d_inode;
- static struct dentry *dentry;
+ struct dentry *dentry;
struct btrfs_root *root = BTRFS_I(dir)->root;
struct btrfs_path *path;
struct extent_buffer *leaf;
if (dentry->d_fsdata)
return 0;
- if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
+ if (dentry->d_parent == NULL || /* nfs fh_to_dentry */
+ ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
dentry->d_op = &ceph_dentry_ops;
else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
dentry->d_op = &ceph_snapdir_dentry_ops;
static int striped_read(struct inode *inode,
u64 off, u64 len,
struct page **pages, int num_pages,
- int *checkeof, bool align_to_pages)
+ int *checkeof, bool align_to_pages,
+ unsigned long buf_align)
{
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
struct ceph_inode_info *ci = ceph_inode(inode);
more:
if (align_to_pages)
- page_align = (pos - io_align) & ~PAGE_MASK;
+ page_align = (pos - io_align + buf_align) & ~PAGE_MASK;
else
page_align = pos & ~PAGE_MASK;
this_len = left;
struct inode *inode = file->f_dentry->d_inode;
struct page **pages;
u64 off = *poff;
- int num_pages = calc_pages_for(off, len);
- int ret;
+ int num_pages, ret;
dout("sync_read on file %p %llu~%u %s\n", file, off, len,
(file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
- if (file->f_flags & O_DIRECT)
- pages = ceph_get_direct_page_vector(data, num_pages);
- else
+ if (file->f_flags & O_DIRECT) {
+ num_pages = calc_pages_for((unsigned long)data, len);
+ pages = ceph_get_direct_page_vector(data, num_pages, true);
+ } else {
+ num_pages = calc_pages_for(off, len);
pages = ceph_alloc_page_vector(num_pages, GFP_NOFS);
+ }
if (IS_ERR(pages))
return PTR_ERR(pages);
goto done;
ret = striped_read(inode, off, len, pages, num_pages, checkeof,
- file->f_flags & O_DIRECT);
+ file->f_flags & O_DIRECT,
+ (unsigned long)data & ~PAGE_MASK);
if (ret >= 0 && (file->f_flags & O_DIRECT) == 0)
ret = ceph_copy_page_vector_to_user(pages, data, off, ret);
done:
if (file->f_flags & O_DIRECT)
- ceph_put_page_vector(pages, num_pages);
+ ceph_put_page_vector(pages, num_pages, true);
else
ceph_release_page_vector(pages, num_pages);
dout("sync_read result %d\n", ret);
int do_sync = 0;
int check_caps = 0;
int page_align, io_align;
+ unsigned long buf_align;
int ret;
struct timespec mtime = CURRENT_TIME;
pos = *offset;
io_align = pos & ~PAGE_MASK;
+ buf_align = (unsigned long)data & ~PAGE_MASK;
ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left);
if (ret < 0)
*/
more:
len = left;
- if (file->f_flags & O_DIRECT)
+ if (file->f_flags & O_DIRECT) {
/* write from beginning of first page, regardless of
io alignment */
- page_align = (pos - io_align) & ~PAGE_MASK;
- else
+ page_align = (pos - io_align + buf_align) & ~PAGE_MASK;
+ num_pages = calc_pages_for((unsigned long)data, len);
+ } else {
page_align = pos & ~PAGE_MASK;
+ num_pages = calc_pages_for(pos, len);
+ }
req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
ceph_vino(inode), pos, &len,
CEPH_OSD_OP_WRITE, flags,
if (!req)
return -ENOMEM;
- num_pages = calc_pages_for(pos, len);
-
if (file->f_flags & O_DIRECT) {
- pages = ceph_get_direct_page_vector(data, num_pages);
+ pages = ceph_get_direct_page_vector(data, num_pages, false);
if (IS_ERR(pages)) {
ret = PTR_ERR(pages);
goto out;
}
if (file->f_flags & O_DIRECT)
- ceph_put_page_vector(pages, num_pages);
+ ceph_put_page_vector(pages, num_pages, false);
else if (file->f_flags & O_SYNC)
ceph_release_page_vector(pages, num_pages);
GFP_NOFS);
if (err)
goto exit_bh;
+ for (i = 0, bit = gdblocks + 1; i < reserved_gdb; i++, bit++)
+ ext4_set_bit(bit, bh->b_data);
ext4_debug("mark block bitmap %#04llx (+%llu)\n", input->block_bitmap,
input->block_bitmap - start);
err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, GFP_NOFS);
if (err)
goto exit_bh;
+ for (i = 0, bit = input->inode_table - start;
+ i < sbi->s_itb_per_group; i++, bit++)
+ ext4_set_bit(bit, bh->b_data);
if ((err = extend_or_restart_transaction(handle, 2, bh)))
goto exit_bh;
super->s_journal_seg[i] = segno;
super->s_journal_ec[i] = ec;
logfs_set_segment_reserved(sb, segno);
- err = btree_insert32(head, segno, (void *)1, GFP_KERNEL);
+ err = btree_insert32(head, segno, (void *)1, GFP_NOFS);
BUG_ON(err); /* mempool should prevent this */
err = logfs_erase_segment(sb, segno, 1);
BUG_ON(err); /* FIXME: remount-ro would be nicer */
/* FIXME: transaction is part of logfs_block now. Is that enough? */
err = logfs_write_buf(master_inode, page, 0);
+ if (err)
+ move_page_to_inode(inode, page);
+
logfs_put_write_page(page);
return err;
}
if (!(open_flag & O_CREAT))
mode = 0;
+ /* Must never be set by userspace */
+ open_flag &= ~FMODE_NONOTIFY;
+
/*
* O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only
* check for O_DSYNC if the need any syncing at all we enforce it's
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/sched.h>
-#include <linux/vmalloc.h>
#include <linux/kmemleak.h>
#include <linux/xattr.h>
/* Perform conversion from xdr to cache array */
static
int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
- void *xdr_page, struct page *page, unsigned int buflen)
+ struct page **xdr_pages, struct page *page, unsigned int buflen)
{
struct xdr_stream stream;
- struct xdr_buf buf;
- __be32 *ptr = xdr_page;
+ struct xdr_buf buf = {
+ .pages = xdr_pages,
+ .page_len = buflen,
+ .buflen = buflen,
+ .len = buflen,
+ };
+ struct page *scratch;
struct nfs_cache_array *array;
unsigned int count = 0;
int status;
- buf.head->iov_base = xdr_page;
- buf.head->iov_len = buflen;
- buf.tail->iov_len = 0;
- buf.page_base = 0;
- buf.page_len = 0;
- buf.buflen = buf.head->iov_len;
- buf.len = buf.head->iov_len;
-
- xdr_init_decode(&stream, &buf, ptr);
+ scratch = alloc_page(GFP_KERNEL);
+ if (scratch == NULL)
+ return -ENOMEM;
+ xdr_init_decode(&stream, &buf, NULL);
+ xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
do {
status = xdr_decode(desc, entry, &stream);
} else
status = PTR_ERR(array);
}
+
+ put_page(scratch);
return status;
}
void nfs_readdir_free_large_page(void *ptr, struct page **pages,
unsigned int npages)
{
- vm_unmap_ram(ptr, npages);
nfs_readdir_free_pagearray(pages, npages);
}
* to nfs_readdir_free_large_page
*/
static
-void *nfs_readdir_large_page(struct page **pages, unsigned int npages)
+int nfs_readdir_large_page(struct page **pages, unsigned int npages)
{
- void *ptr;
unsigned int i;
for (i = 0; i < npages; i++) {
goto out_freepages;
pages[i] = page;
}
+ return 0;
- ptr = vm_map_ram(pages, npages, 0, PAGE_KERNEL);
- if (!IS_ERR_OR_NULL(ptr))
- return ptr;
out_freepages:
nfs_readdir_free_pagearray(pages, i);
- return NULL;
+ return -ENOMEM;
}
static
memset(array, 0, sizeof(struct nfs_cache_array));
array->eof_index = -1;
- pages_ptr = nfs_readdir_large_page(pages, array_size);
- if (!pages_ptr)
+ status = nfs_readdir_large_page(pages, array_size);
+ if (status < 0)
goto out_release_array;
do {
unsigned int pglen;
if (status < 0)
break;
pglen = status;
- status = nfs_readdir_page_filler(desc, &entry, pages_ptr, page, pglen);
+ status = nfs_readdir_page_filler(desc, &entry, pages, page, pglen);
if (status < 0) {
if (status == -ENOSPC)
status = 0;
entry->d_type = DT_UNKNOWN;
- /* Peek at the next entry to see if we're at EOD */
- p = xdr_inline_peek(xdr, 4 + 4);
- entry->eof = 0;
- if (p != NULL)
- entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
return 0;
out_overflow:
zero_nfs_fh3(entry->fh);
}
- /* Peek at the next entry to see if we're at EOD */
- p = xdr_inline_peek(xdr, 4 + 4);
- entry->eof = 0;
- if (p != NULL)
- entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
return 0;
out_overflow:
if (verify_attr_len(xdr, p, len) < 0)
goto out_overflow;
- p = xdr_inline_peek(xdr, 8);
- if (p != NULL)
- entry->eof = !p[0] && p[1];
- else
- entry->eof = 0;
-
return 0;
out_overflow:
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
- wait_event(group->fanotify_data.access_waitq, event->response);
+ wait_event(group->fanotify_data.access_waitq, event->response ||
+ atomic_read(&group->fanotify_data.bypass_perm));
+
+ if (!event->response) /* bypass_perm set */
+ return 0;
/* userspace responded, convert to something usable */
spin_lock(&event->lock);
return client_fd;
}
-static ssize_t fill_event_metadata(struct fsnotify_group *group,
+static int fill_event_metadata(struct fsnotify_group *group,
struct fanotify_event_metadata *metadata,
struct fsnotify_event *event)
{
+ int ret = 0;
+
pr_debug("%s: group=%p metadata=%p event=%p\n", __func__,
group, metadata, event);
metadata->event_len = FAN_EVENT_METADATA_LEN;
+ metadata->metadata_len = FAN_EVENT_METADATA_LEN;
metadata->vers = FANOTIFY_METADATA_VERSION;
metadata->mask = event->mask & FAN_ALL_OUTGOING_EVENTS;
metadata->pid = pid_vnr(event->tgid);
- metadata->fd = create_fd(group, event);
+ if (unlikely(event->mask & FAN_Q_OVERFLOW))
+ metadata->fd = FAN_NOFD;
+ else {
+ metadata->fd = create_fd(group, event);
+ if (metadata->fd < 0)
+ ret = metadata->fd;
+ }
- return metadata->fd;
+ return ret;
}
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
mutex_lock(&group->fanotify_data.access_mutex);
- if (group->fanotify_data.bypass_perm) {
+ if (atomic_read(&group->fanotify_data.bypass_perm)) {
mutex_unlock(&group->fanotify_data.access_mutex);
kmem_cache_free(fanotify_response_event_cache, re);
event->response = FAN_ALLOW;
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
- fd = fill_event_metadata(group, &fanotify_event_metadata, event);
- if (fd < 0)
- return fd;
+ ret = fill_event_metadata(group, &fanotify_event_metadata, event);
+ if (ret < 0)
+ goto out;
+ fd = fanotify_event_metadata.fd;
ret = prepare_for_access_response(group, event, fd);
if (ret)
goto out_close_fd;
ret = -EFAULT;
- if (copy_to_user(buf, &fanotify_event_metadata, FAN_EVENT_METADATA_LEN))
+ if (copy_to_user(buf, &fanotify_event_metadata,
+ fanotify_event_metadata.event_len))
goto out_kill_access_response;
- return FAN_EVENT_METADATA_LEN;
+ return fanotify_event_metadata.event_len;
out_kill_access_response:
remove_access_response(group, event, fd);
out_close_fd:
- sys_close(fd);
+ if (fd != FAN_NOFD)
+ sys_close(fd);
+out:
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+ if (event->mask & FAN_ALL_PERM_EVENTS) {
+ event->response = FAN_DENY;
+ wake_up(&group->fanotify_data.access_waitq);
+ }
+#endif
return ret;
}
mutex_lock(&group->fanotify_data.access_mutex);
- group->fanotify_data.bypass_perm = true;
+ atomic_inc(&group->fanotify_data.bypass_perm);
list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) {
pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group,
{
struct fsnotify_mark *fsn_mark;
__u32 added;
+ int ret = 0;
fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
if (!fsn_mark) {
- int ret;
-
if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks)
return -ENOSPC;
fsnotify_init_mark(fsn_mark, fanotify_free_mark);
ret = fsnotify_add_mark(fsn_mark, group, NULL, mnt, 0);
- if (ret) {
- fanotify_free_mark(fsn_mark);
- return ret;
- }
+ if (ret)
+ goto err;
}
added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
- fsnotify_put_mark(fsn_mark);
+
if (added & ~mnt->mnt_fsnotify_mask)
fsnotify_recalc_vfsmount_mask(mnt);
-
- return 0;
+err:
+ fsnotify_put_mark(fsn_mark);
+ return ret;
}
static int fanotify_add_inode_mark(struct fsnotify_group *group,
{
struct fsnotify_mark *fsn_mark;
__u32 added;
+ int ret = 0;
pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
fsn_mark = fsnotify_find_inode_mark(group, inode);
if (!fsn_mark) {
- int ret;
-
if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks)
return -ENOSPC;
fsnotify_init_mark(fsn_mark, fanotify_free_mark);
ret = fsnotify_add_mark(fsn_mark, group, inode, NULL, 0);
- if (ret) {
- fanotify_free_mark(fsn_mark);
- return ret;
- }
+ if (ret)
+ goto err;
}
added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
- fsnotify_put_mark(fsn_mark);
+
if (added & ~inode->i_fsnotify_mask)
fsnotify_recalc_inode_mask(inode);
- return 0;
+err:
+ fsnotify_put_mark(fsn_mark);
+ return ret;
}
/* fanotify syscalls */
/* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */
group = fsnotify_alloc_group(&fanotify_fsnotify_ops);
- if (IS_ERR(group))
+ if (IS_ERR(group)) {
+ free_uid(user);
return PTR_ERR(group);
+ }
group->fanotify_data.user = user;
atomic_inc(&user->fanotify_listeners);
mutex_init(&group->fanotify_data.access_mutex);
init_waitqueue_head(&group->fanotify_data.access_waitq);
INIT_LIST_HEAD(&group->fanotify_data.access_list);
+ atomic_set(&group->fanotify_data.bypass_perm, 0);
#endif
switch (flags & FAN_ALL_CLASS_BITS) {
case FAN_CLASS_NOTIF:
if (flags & ~FAN_ALL_MARK_FLAGS)
return -EINVAL;
switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
- case FAN_MARK_ADD:
+ case FAN_MARK_ADD: /* fallthrough */
case FAN_MARK_REMOVE:
+ if (!mask)
+ return -EINVAL;
case FAN_MARK_FLUSH:
break;
default:
if (ret >= 0)
return ret;
+ fsnotify_put_group(group);
atomic_dec(&user->inotify_devs);
out_free_uid:
free_uid(user);
/* this io's submitter should not have unlocked this before we could */
BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
+ if (ocfs2_iocb_is_sem_locked(iocb)) {
+ up_read(&inode->i_alloc_sem);
+ ocfs2_iocb_clear_sem_locked(iocb);
+ }
+
ocfs2_iocb_clear_rw_locked(iocb);
level = ocfs2_iocb_rw_locked_level(iocb);
- if (!level)
- up_read(&inode->i_alloc_sem);
ocfs2_rw_unlock(inode, level);
if (is_async)
else
clear_bit(1, (unsigned long *)&iocb->private);
}
+
+/*
+ * Using a named enum representing lock types in terms of #N bit stored in
+ * iocb->private, which is going to be used for communication bewteen
+ * ocfs2_dio_end_io() and ocfs2_file_aio_write/read().
+ */
+enum ocfs2_iocb_lock_bits {
+ OCFS2_IOCB_RW_LOCK = 0,
+ OCFS2_IOCB_RW_LOCK_LEVEL,
+ OCFS2_IOCB_SEM,
+ OCFS2_IOCB_NUM_LOCKS
+};
+
#define ocfs2_iocb_clear_rw_locked(iocb) \
- clear_bit(0, (unsigned long *)&iocb->private)
+ clear_bit(OCFS2_IOCB_RW_LOCK, (unsigned long *)&iocb->private)
#define ocfs2_iocb_rw_locked_level(iocb) \
- test_bit(1, (unsigned long *)&iocb->private)
+ test_bit(OCFS2_IOCB_RW_LOCK_LEVEL, (unsigned long *)&iocb->private)
+#define ocfs2_iocb_set_sem_locked(iocb) \
+ set_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private)
+#define ocfs2_iocb_clear_sem_locked(iocb) \
+ clear_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private)
+#define ocfs2_iocb_is_sem_locked(iocb) \
+ test_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private)
#endif /* OCFS2_FILE_H */
define_mask(QUOTA),
define_mask(REFCOUNT),
define_mask(BASTS),
+ define_mask(RESERVATIONS),
+ define_mask(CLUSTER),
define_mask(ERROR),
define_mask(NOTICE),
define_mask(KTHREAD),
- define_mask(RESERVATIONS),
};
static struct attribute *mlog_attr_ptrs[MLOG_MAX_BITS] = {NULL, };
#include <linux/sched.h>
/* bits that are frequently given and infrequently matched in the low word */
-/* NOTE: If you add a flag, you need to also update mlog.c! */
+/* NOTE: If you add a flag, you need to also update masklog.c! */
#define ML_ENTRY 0x0000000000000001ULL /* func call entry */
#define ML_EXIT 0x0000000000000002ULL /* func call exit */
#define ML_TCP 0x0000000000000004ULL /* net cluster/tcp.c */
#define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */
#define ML_QUOTA 0x0000000040000000ULL /* ocfs2 quota operations */
#define ML_REFCOUNT 0x0000000080000000ULL /* refcount tree operations */
-#define ML_BASTS 0x0000001000000000ULL /* dlmglue asts and basts */
+#define ML_BASTS 0x0000000100000000ULL /* dlmglue asts and basts */
+#define ML_RESERVATIONS 0x0000000200000000ULL /* ocfs2 alloc reservations */
+#define ML_CLUSTER 0x0000000400000000ULL /* cluster stack */
+
/* bits that are infrequently given and frequently matched in the high word */
-#define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */
-#define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */
-#define ML_KTHREAD 0x0000000400000000ULL /* kernel thread activity */
-#define ML_RESERVATIONS 0x0000000800000000ULL /* ocfs2 alloc reservations */
-#define ML_CLUSTER 0x0000001000000000ULL /* cluster stack */
+#define ML_ERROR 0x1000000000000000ULL /* sent to KERN_ERR */
+#define ML_NOTICE 0x2000000000000000ULL /* setn to KERN_NOTICE */
+#define ML_KTHREAD 0x4000000000000000ULL /* kernel thread activity */
#define MLOG_INITIAL_AND_MASK (ML_ERROR|ML_NOTICE)
#define MLOG_INITIAL_NOT_MASK (ML_ENTRY|ML_EXIT)
di->i_dx_root = cpu_to_le64(dr_blkno);
+ spin_lock(&OCFS2_I(dir)->ip_lock);
OCFS2_I(dir)->ip_dyn_features |= OCFS2_INDEXED_DIR_FL;
di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features);
+ spin_unlock(&OCFS2_I(dir)->ip_lock);
ocfs2_journal_dirty(handle, di_bh);
goto out_commit;
}
+ spin_lock(&OCFS2_I(dir)->ip_lock);
OCFS2_I(dir)->ip_dyn_features &= ~OCFS2_INDEXED_DIR_FL;
di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features);
+ spin_unlock(&OCFS2_I(dir)->ip_lock);
di->i_dx_root = cpu_to_le64(0ULL);
ocfs2_journal_dirty(handle, di_bh);
*/
static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res,
- int *numlocks)
+ int *numlocks,
+ int *hasrefs)
{
int ret;
int i;
assert_spin_locked(&res->spinlock);
+ *numlocks = 0;
+ *hasrefs = 0;
+
ret = -EINVAL;
if (res->owner == DLM_LOCK_RES_OWNER_UNKNOWN) {
mlog(0, "cannot migrate lockres with unknown owner!\n");
}
*numlocks = count;
- mlog(0, "migrateable lockres having %d locks\n", *numlocks);
+
+ count = find_next_bit(res->refmap, O2NM_MAX_NODES, 0);
+ if (count < O2NM_MAX_NODES)
+ *hasrefs = 1;
+
+ mlog(0, "%s: res %.*s, Migrateable, locks %d, refs %d\n", dlm->name,
+ res->lockname.len, res->lockname.name, *numlocks, *hasrefs);
leave:
return ret;
const char *name;
unsigned int namelen;
int mle_added = 0;
- int numlocks;
+ int numlocks, hasrefs;
int wake = 0;
if (!dlm_grab(dlm))
name = res->lockname.name;
namelen = res->lockname.len;
- mlog(0, "migrating %.*s to %u\n", namelen, name, target);
+ mlog(0, "%s: Migrating %.*s to %u\n", dlm->name, namelen, name, target);
/*
* ensure this lockres is a proper candidate for migration
*/
spin_lock(&res->spinlock);
- ret = dlm_is_lockres_migrateable(dlm, res, &numlocks);
+ ret = dlm_is_lockres_migrateable(dlm, res, &numlocks, &hasrefs);
if (ret < 0) {
spin_unlock(&res->spinlock);
goto leave;
spin_unlock(&res->spinlock);
/* no work to do */
- if (numlocks == 0) {
- mlog(0, "no locks were found on this lockres! done!\n");
+ if (numlocks == 0 && !hasrefs)
goto leave;
- }
/*
* preallocate up front
* find a node to migrate the lockres to
*/
- mlog(0, "picking a migration node\n");
spin_lock(&dlm->spinlock);
/* pick a new node */
if (!test_bit(target, dlm->domain_map) ||
target >= O2NM_MAX_NODES) {
target = dlm_pick_migration_target(dlm, res);
}
- mlog(0, "node %u chosen for migration\n", target);
+ mlog(0, "%s: res %.*s, Node %u chosen for migration\n", dlm->name,
+ namelen, name, target);
if (target >= O2NM_MAX_NODES ||
!test_bit(target, dlm->domain_map)) {
{
int ret;
int lock_dropped = 0;
- int numlocks;
+ int numlocks, hasrefs;
spin_lock(&res->spinlock);
if (res->owner != dlm->node_num) {
}
/* No need to migrate a lockres having no locks */
- ret = dlm_is_lockres_migrateable(dlm, res, &numlocks);
- if (ret >= 0 && numlocks == 0) {
+ ret = dlm_is_lockres_migrateable(dlm, res, &numlocks, &hasrefs);
+ if (ret >= 0 && numlocks == 0 && !hasrefs) {
spin_unlock(&res->spinlock);
goto leave;
}
}
queue++;
}
+
+ nodenum = find_next_bit(res->refmap, O2NM_MAX_NODES, 0);
+ if (nodenum < O2NM_MAX_NODES) {
+ spin_unlock(&res->spinlock);
+ return nodenum;
+ }
spin_unlock(&res->spinlock);
mlog(0, "have not found a suitable target yet! checking domain map\n");
mutex_lock(&inode->i_mutex);
+ ocfs2_iocb_clear_sem_locked(iocb);
+
relock:
/* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */
if (direct_io) {
down_read(&inode->i_alloc_sem);
have_alloc_sem = 1;
+ /* communicate with ocfs2_dio_end_io */
+ ocfs2_iocb_set_sem_locked(iocb);
}
/*
ocfs2_rw_unlock(inode, rw_level);
out_sems:
- if (have_alloc_sem)
+ if (have_alloc_sem) {
up_read(&inode->i_alloc_sem);
+ ocfs2_iocb_clear_sem_locked(iocb);
+ }
mutex_unlock(&inode->i_mutex);
goto bail;
}
+ ocfs2_iocb_clear_sem_locked(iocb);
+
/*
* buffered reads protect themselves in ->readpage(). O_DIRECT reads
* need locks to protect pending reads from racing with truncate.
if (filp->f_flags & O_DIRECT) {
down_read(&inode->i_alloc_sem);
have_alloc_sem = 1;
+ ocfs2_iocb_set_sem_locked(iocb);
ret = ocfs2_rw_lock(inode, 0);
if (ret < 0) {
}
bail:
- if (have_alloc_sem)
+ if (have_alloc_sem) {
up_read(&inode->i_alloc_sem);
+ ocfs2_iocb_clear_sem_locked(iocb);
+ }
if (rw_level != -1)
ocfs2_rw_unlock(inode, rw_level);
mlog_exit(ret);
#define OCFS2_LAST_LOCAL_SYSTEM_INODE LOCAL_GROUP_QUOTA_SYSTEM_INODE
NUM_SYSTEM_INODES
};
-#define NUM_GLOBAL_SYSTEM_INODES OCFS2_LAST_GLOBAL_SYSTEM_INODE
+#define NUM_GLOBAL_SYSTEM_INODES OCFS2_FIRST_LOCAL_SYSTEM_INODE
#define NUM_LOCAL_SYSTEM_INODES \
(NUM_SYSTEM_INODES - OCFS2_FIRST_LOCAL_SYSTEM_INODE)
unsigned char misaligned;
unsigned char discard_misaligned;
- unsigned char no_cluster;
+ unsigned char cluster;
signed char discard_zeroes_data;
};
#endif
};
-#define QUEUE_FLAG_CLUSTER 0 /* cluster several segments into 1 */
#define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */
#define QUEUE_FLAG_STOPPED 2 /* queue is stopped */
#define QUEUE_FLAG_SYNCFULL 3 /* read queue has been filled */
#define QUEUE_FLAG_SECDISCARD 19 /* supports SECDISCARD */
#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \
- (1 << QUEUE_FLAG_CLUSTER) | \
(1 << QUEUE_FLAG_STACKABLE) | \
(1 << QUEUE_FLAG_SAME_COMP) | \
(1 << QUEUE_FLAG_ADD_RANDOM))
#define rq_data_dir(rq) ((rq)->cmd_flags & 1)
+static inline unsigned int blk_queue_cluster(struct request_queue *q)
+{
+ return q->limits.cluster;
+}
+
/*
* We regard a request as sync, if either a read or a sync write
*/
extern void blk_cleanup_queue(struct request_queue *);
extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
extern void blk_queue_bounce_limit(struct request_queue *, u64);
+extern void blk_limits_max_hw_sectors(struct queue_limits *, unsigned int);
extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int);
extern void blk_queue_max_segments(struct request_queue *, unsigned short);
extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
#define alloc_bootmem(x) \
__alloc_bootmem(x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+#define alloc_bootmem_align(x, align) \
+ __alloc_bootmem(x, align, __pa(MAX_DMA_ADDRESS))
#define alloc_bootmem_nopanic(x) \
__alloc_bootmem_nopanic(x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
#define alloc_bootmem_pages(x) \
extern void ceph_release_page_vector(struct page **pages, int num_pages);
extern struct page **ceph_get_direct_page_vector(const char __user *data,
- int num_pages);
-extern void ceph_put_page_vector(struct page **pages, int num_pages);
+ int num_pages,
+ bool write_page);
+extern void ceph_put_page_vector(struct page **pages, int num_pages,
+ bool dirty);
extern void ceph_release_page_vector(struct page **pages, int num_pages);
extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
extern int ceph_copy_user_to_page_vector(struct page **pages,
*
* 2) this code must not be preempted for a duration longer than the
* 32-bit counter half period minus the longest period between two
- * calls to this code.
+ * calls to this code;
*
* Those requirements ensure proper update to the state bit in memory.
* This is usually not a problem in practice, but if it is then a kernel
* timer should be scheduled to manage for this code to be executed often
* enough.
*
+ * And finally:
+ *
+ * 3) the cnt_lo argument must be seen as a globally incrementing value,
+ * meaning that it should be a direct reference to the counter data which
+ * can be evaluated according to a specific ordering within the macro,
+ * and not the result of a previous evaluation stored in a variable.
+ *
+ * For example, this is wrong:
+ *
+ * u32 partial = get_hw_count();
+ * u64 full = cnt32_to_63(partial);
+ * return full;
+ *
+ * This is fine:
+ *
+ * u64 full = cnt32_to_63(get_hw_count());
+ * return full;
+ *
* Note that the top bit (bit 63) in the returned value should be considered
* as garbage. It is not cleared here because callers are likely to use a
* multiplier on the returned value which can get rid of the top bit
#ifdef CONFIG_DMA_ENGINE
enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
void dma_issue_pending_all(void);
+struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param);
+void dma_release_channel(struct dma_chan *chan);
#else
static inline enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx)
{
}
static inline void dma_issue_pending_all(void)
{
- do { } while (0);
+}
+static inline struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask,
+ dma_filter_fn fn, void *fn_param)
+{
+ return NULL;
+}
+static inline void dma_release_channel(struct dma_chan *chan)
+{
}
#endif
void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type);
#define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y)
-struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param);
-void dma_release_channel(struct dma_chan *chan);
/* --- Helper iov-locking functions --- */
FAN_ALL_PERM_EVENTS |\
FAN_Q_OVERFLOW)
-#define FANOTIFY_METADATA_VERSION 2
+#define FANOTIFY_METADATA_VERSION 3
struct fanotify_event_metadata {
__u32 event_len;
- __u32 vers;
+ __u8 vers;
+ __u8 reserved;
+ __u16 metadata_len;
__aligned_u64 mask;
__s32 fd;
__s32 pid;
struct fanotify_response {
__s32 fd;
__u32 response;
-} __attribute__ ((packed));
+};
/* Legit userspace responses to a _PERM event */
#define FAN_ALLOW 0x01
#define FAN_DENY 0x02
+/* No fd set in event */
+#define FAN_NOFD -1
/* Helper functions to deal with fanotify_event_metadata buffers */
#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata))
if (S_ISDIR(inode->i_mode))
mask |= FS_ISDIR;
- /* FMODE_NONOTIFY must never be set from user */
- file->f_mode &= ~FMODE_NONOTIFY;
-
fsnotify_parent(path, NULL, mask);
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
}
struct mutex access_mutex;
struct list_head access_list;
wait_queue_head_t access_waitq;
- bool bypass_perm; /* protected by access_mutex */
+ atomic_t bypass_perm;
#endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */
int f_flags;
unsigned int max_marks;
/* PC/ISA/whatever - the normal PC address spaces: IO and memory */
extern struct resource ioport_resource;
extern struct resource iomem_resource;
-extern int resource_alloc_from_bottom;
extern struct resource *request_resource_conflict(struct resource *root, struct resource *new);
extern int request_resource(struct resource *root, struct resource *new);
extern struct resource *insert_resource_conflict(struct resource *parent, struct resource *new);
extern int insert_resource(struct resource *parent, struct resource *new);
extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new);
+extern void arch_remove_reservations(struct resource *avail);
extern int allocate_resource(struct resource *root, struct resource *new,
resource_size_t size, resource_size_t min,
resource_size_t max, resource_size_t align,
#define DEFINE_KTHREAD_WORK(work, fn) \
struct kthread_work work = KTHREAD_WORK_INIT(work, fn)
-static inline void init_kthread_worker(struct kthread_worker *worker)
-{
- *worker = (struct kthread_worker)KTHREAD_WORKER_INIT(*worker);
-}
-
-static inline void init_kthread_work(struct kthread_work *work,
- kthread_work_func_t fn)
-{
- *work = (struct kthread_work)KTHREAD_WORK_INIT(*work, fn);
-}
+/*
+ * kthread_worker.lock and kthread_work.done need their own lockdep class
+ * keys if they are defined on stack with lockdep enabled. Use the
+ * following macros when defining them on stack.
+ */
+#ifdef CONFIG_LOCKDEP
+# define KTHREAD_WORKER_INIT_ONSTACK(worker) \
+ ({ init_kthread_worker(&worker); worker; })
+# define DEFINE_KTHREAD_WORKER_ONSTACK(worker) \
+ struct kthread_worker worker = KTHREAD_WORKER_INIT_ONSTACK(worker)
+# define KTHREAD_WORK_INIT_ONSTACK(work, fn) \
+ ({ init_kthread_work((&work), fn); work; })
+# define DEFINE_KTHREAD_WORK_ONSTACK(work, fn) \
+ struct kthread_work work = KTHREAD_WORK_INIT_ONSTACK(work, fn)
+#else
+# define DEFINE_KTHREAD_WORKER_ONSTACK(worker) DEFINE_KTHREAD_WORKER(worker)
+# define DEFINE_KTHREAD_WORK_ONSTACK(work, fn) DEFINE_KTHREAD_WORK(work, fn)
+#endif
+
+extern void __init_kthread_worker(struct kthread_worker *worker,
+ const char *name, struct lock_class_key *key);
+
+#define init_kthread_worker(worker) \
+ do { \
+ static struct lock_class_key __key; \
+ __init_kthread_worker((worker), "("#worker")->lock", &__key); \
+ } while (0)
+
+#define init_kthread_work(work, fn) \
+ do { \
+ memset((work), 0, sizeof(struct kthread_work)); \
+ INIT_LIST_HEAD(&(work)->node); \
+ (work)->func = (fn); \
+ init_waitqueue_head(&(work)->done); \
+ } while (0)
int kthread_worker_fn(void *worker_ptr);
Check NLM_F_EXCL
*/
-#define NLMSG_ALIGNTO 4
+#define NLMSG_ALIGNTO 4U
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
int exclusive;
struct list_head rotation_list;
int jiffies_interval;
+ struct pmu *active_pmu;
};
struct perf_output_handle {
static inline bool pm_runtime_suspended(struct device *dev)
{
- return dev->power.runtime_status == RPM_SUSPENDED;
+ return dev->power.runtime_status == RPM_SUSPENDED
+ && !dev->power.disable_depth;
}
static inline void pm_runtime_mark_last_busy(struct device *dev)
extern unsigned long this_cpu_load(void);
-extern void calc_global_load(void);
+extern void calc_global_load(unsigned long ticks);
extern unsigned long get_parent_ip(unsigned long addr);
return 0;
}
-extern char * nvram_get(const char *name);
+#ifdef CONFIG_BCM47XX
+#include <asm/mach-bcm47xx/nvram.h>
/* Get the device MAC address */
static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
{
-#ifdef CONFIG_BCM47XX
- char *res = nvram_get("et0macaddr");
- if (res)
- memcpy(macaddr, res, 6);
-#endif
+ char buf[20];
+ if (nvram_getenv("et0macaddr", buf, sizeof(buf)) < 0)
+ return;
+ nvram_parse_macaddr(buf, macaddr);
}
+#else
+static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
+{
+}
+#endif
extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
struct pci_dev *pdev);
__be32 *end; /* end of available buffer space */
struct kvec *iov; /* pointer to the current kvec */
+ struct kvec scratch; /* Scratch buffer */
+ struct page **page_ptr; /* pointer to the current page */
};
/*
extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
unsigned int base, unsigned int len);
extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
-extern __be32 *xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes);
+extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen);
extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
*/
-#define TASKSTATS_VERSION 7
+#define TASKSTATS_VERSION 8
#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN
* in linux/sched.h */
TASKSTATS_TYPE_STATS, /* taskstats structure */
TASKSTATS_TYPE_AGGR_PID, /* contains pid + stats */
TASKSTATS_TYPE_AGGR_TGID, /* contains tgid + stats */
+ TASKSTATS_TYPE_NULL, /* contains nothing */
__TASKSTATS_TYPE_MAX,
};
#include <linux/kernel.h>
-struct __una_u16 { u16 x __attribute__((packed)); };
-struct __una_u32 { u32 x __attribute__((packed)); };
-struct __una_u64 { u64 x __attribute__((packed)); };
+struct __una_u16 { u16 x; } __attribute__((packed));
+struct __una_u32 { u32 x; } __attribute__((packed));
+struct __una_u64 { u64 x; } __attribute__((packed));
static inline u16 __get_unaligned_cpu16(const void *p)
{
extern struct mutex saa7146_devices_lock;
int saa7146_register_extension(struct saa7146_extension*);
int saa7146_unregister_extension(struct saa7146_extension*);
-struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc);
+struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc);
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt);
void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
unsigned int notification, void *arg);
/* The control handler. May be NULL. */
struct v4l2_ctrl_handler *ctrl_handler;
+ /* BKL replacement mutex. Temporary solution only. */
+ struct mutex ioctl_lock;
};
/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev.
#define WM8775_AIN3 4
#define WM8775_AIN4 8
-/* subdev group ID */
-#define WM8775_GID (1 << 0)
-
#endif
__u8 proto;
__u8 flags;
#define FLOWI_FLAG_ANYSRC 0x01
-#define FLOWI_FLAG_MATCH_ANY_IIF 0x02
union {
struct {
__be16 sport;
return rt->rt6i_flags & RTF_LOCAL;
}
+int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
+
+static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
+{
+ struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
+
+ return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ?
+ skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
+}
+
#endif
#endif
*
* This function may not be called in IRQ context. Calls to this function
* for a single hardware must be synchronized against each other. Calls
- * to this function and ieee80211_tx_status_irqsafe() may not be mixed
- * for a single hardware.
+ * to this function, ieee80211_tx_status_ni() and ieee80211_tx_status_irqsafe()
+ * may not be mixed for a single hardware.
*
* @hw: the hardware the frame was transmitted by
* @skb: the frame that was transmitted, owned by mac80211 after this call
struct sk_buff *skb);
/**
+ * ieee80211_tx_status_ni - transmit status callback (in process context)
+ *
+ * Like ieee80211_tx_status() but can be called in process context.
+ *
+ * Calls to this function, ieee80211_tx_status() and
+ * ieee80211_tx_status_irqsafe() may not be mixed
+ * for a single hardware.
+ *
+ * @hw: the hardware the frame was transmitted by
+ * @skb: the frame that was transmitted, owned by mac80211 after this call
+ */
+static inline void ieee80211_tx_status_ni(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ local_bh_disable();
+ ieee80211_tx_status(hw, skb);
+ local_bh_enable();
+}
+
+/**
* ieee80211_tx_status_irqsafe - IRQ-safe transmit status callback
*
* Like ieee80211_tx_status() but can be called in IRQ context
* (internally defers to a tasklet.)
*
- * Calls to this function and ieee80211_tx_status() may not be mixed for a
- * single hardware.
+ * Calls to this function, ieee80211_tx_status() and
+ * ieee80211_tx_status_ni() may not be mixed for a single hardware.
*
* @hw: the hardware the frame was transmitted by
* @skb: the frame that was transmitted, owned by mac80211 after this call
static inline int tcf_valid_offset(const struct sk_buff *skb,
const unsigned char *ptr, const int len)
{
- return unlikely((ptr + len) < skb_tail_pointer(skb) && ptr > skb->head);
+ return likely((ptr + len) <= skb_tail_pointer(skb) &&
+ ptr >= skb->head &&
+ (ptr <= (ptr + len)));
}
#ifdef CONFIG_NET_CLS_IND
{
struct sk_buff *n;
- if ((action == TC_ACT_STOLEN || action == TC_ACT_QUEUED) &&
- !skb_shared(skb))
- n = skb_get(skb);
- else
- n = skb_clone(skb, gfp_mask);
+ n = skb_clone(skb, gfp_mask);
if (n) {
n->tc_verd = SET_TC_VERD(n->tc_verd, 0);
void (*unhash)(struct sock *sk);
void (*rehash)(struct sock *sk);
int (*get_port)(struct sock *sk, unsigned short snum);
+ void (*clear_sk)(struct sock *sk, int size);
/* Keeping track of sockets in use */
#ifdef CONFIG_PROC_FS
sk->sk_prot->hash(sk);
}
+void sk_prot_clear_portaddr_nulls(struct sock *sk, int size);
+
/* About 10 seconds */
#define SOCK_DESTROY_TIME (10*HZ)
*
* Returns the matching dev_t on success or 0 on failure.
*/
-static dev_t __init devt_from_partuuid(char *uuid_str)
+static dev_t devt_from_partuuid(char *uuid_str)
{
dev_t res = 0;
struct device *dev = NULL;
setup_thread_stack(tsk, orig);
clear_user_return_notifier(tsk);
+ clear_tsk_need_resched(tsk);
stackend = end_of_stack(tsk);
*stackend = STACK_END_MAGIC; /* for overflow detection */
return 0;
}
+void __init_kthread_worker(struct kthread_worker *worker,
+ const char *name,
+ struct lock_class_key *key)
+{
+ spin_lock_init(&worker->lock);
+ lockdep_set_class_and_name(&worker->lock, key, name);
+ INIT_LIST_HEAD(&worker->work_list);
+ worker->task = NULL;
+}
+EXPORT_SYMBOL_GPL(__init_kthread_worker);
+
/**
* kthread_worker_fn - kthread function to process kthread_worker
* @worker_ptr: pointer to initialized kthread_worker
rcu_read_lock();
list_for_each_entry_rcu(pmu, &pmus, entry) {
cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
+ if (cpuctx->active_pmu != pmu)
+ goto next;
perf_event_task_ctx(&cpuctx->ctx, task_event);
ctx = task_event->task_ctx;
rcu_read_lock();
list_for_each_entry_rcu(pmu, &pmus, entry) {
cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
+ if (cpuctx->active_pmu != pmu)
+ goto next;
perf_event_comm_ctx(&cpuctx->ctx, comm_event);
ctxn = pmu->task_ctx_nr;
rcu_read_lock();
list_for_each_entry_rcu(pmu, &pmus, entry) {
cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
+ if (cpuctx->active_pmu != pmu)
+ goto next;
perf_event_mmap_ctx(&cpuctx->ctx, mmap_event,
vma->vm_flags & VM_EXEC);
break;
}
- if (event_id > PERF_COUNT_SW_MAX)
+ if (event_id >= PERF_COUNT_SW_MAX)
return -ENOENT;
if (!event->parent) {
return NULL;
}
-static void free_pmu_context(void * __percpu cpu_context)
+static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu)
{
- struct pmu *pmu;
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct perf_cpu_context *cpuctx;
+
+ cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
+
+ if (cpuctx->active_pmu == old_pmu)
+ cpuctx->active_pmu = pmu;
+ }
+}
+
+static void free_pmu_context(struct pmu *pmu)
+{
+ struct pmu *i;
mutex_lock(&pmus_lock);
/*
* Like a real lame refcount.
*/
- list_for_each_entry(pmu, &pmus, entry) {
- if (pmu->pmu_cpu_context == cpu_context)
+ list_for_each_entry(i, &pmus, entry) {
+ if (i->pmu_cpu_context == pmu->pmu_cpu_context) {
+ update_pmu_context(i, pmu);
goto out;
+ }
}
- free_percpu(cpu_context);
+ free_percpu(pmu->pmu_cpu_context);
out:
mutex_unlock(&pmus_lock);
}
cpuctx->ctx.pmu = pmu;
cpuctx->jiffies_interval = 1;
INIT_LIST_HEAD(&cpuctx->rotation_list);
+ cpuctx->active_pmu = pmu;
}
got_cpu_context:
synchronize_rcu();
free_percpu(pmu->pmu_disable_count);
- free_pmu_context(pmu->pmu_cpu_context);
+ free_pmu_context(pmu);
}
struct pmu *perf_init_event(struct perf_event *event)
#include "power.h"
-#define HIBERNATE_SIG "LINHIB0001"
+#define HIBERNATE_SIG "S1SUSPEND"
/*
* The swap map is a data structure used for keeping track of each page
free_all_swap_pages(data->swap);
if (data->frozen)
thaw_processes();
- pm_notifier_call_chain(data->mode == O_WRONLY ?
+ pm_notifier_call_chain(data->mode == O_RDONLY ?
PM_POST_HIBERNATION : PM_POST_RESTORE);
atomic_inc(&snapshot_device_available);
static DEFINE_RWLOCK(resource_lock);
-/*
- * By default, we allocate free space bottom-up. The architecture can request
- * top-down by clearing this flag. The user can override the architecture's
- * choice with the "resource_alloc_from_bottom" kernel boot option, but that
- * should only be a debugging tool.
- */
-int resource_alloc_from_bottom = 1;
-
-static __init int setup_alloc_from_bottom(char *s)
-{
- printk(KERN_INFO
- "resource: allocating from bottom-up; please report a bug\n");
- resource_alloc_from_bottom = 1;
- return 0;
-}
-early_param("resource_alloc_from_bottom", setup_alloc_from_bottom);
-
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
{
struct resource *p = v;
return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1;
}
+void __weak arch_remove_reservations(struct resource *avail)
+{
+}
+
static resource_size_t simple_align_resource(void *data,
const struct resource *avail,
resource_size_t size,
}
/*
- * Find the resource before "child" in the sibling list of "root" children.
- */
-static struct resource *find_sibling_prev(struct resource *root, struct resource *child)
-{
- struct resource *this;
-
- for (this = root->child; this; this = this->sibling)
- if (this->sibling == child)
- return this;
-
- return NULL;
-}
-
-/*
* Find empty slot in the resource tree given range and alignment.
- * This version allocates from the end of the root resource first.
- */
-static int find_resource_from_top(struct resource *root, struct resource *new,
- resource_size_t size, resource_size_t min,
- resource_size_t max, resource_size_t align,
- resource_size_t (*alignf)(void *,
- const struct resource *,
- resource_size_t,
- resource_size_t),
- void *alignf_data)
-{
- struct resource *this;
- struct resource tmp, avail, alloc;
-
- tmp.start = root->end;
- tmp.end = root->end;
-
- this = find_sibling_prev(root, NULL);
- for (;;) {
- if (this) {
- if (this->end < root->end)
- tmp.start = this->end + 1;
- } else
- tmp.start = root->start;
-
- resource_clip(&tmp, min, max);
-
- /* Check for overflow after ALIGN() */
- avail = *new;
- avail.start = ALIGN(tmp.start, align);
- avail.end = tmp.end;
- if (avail.start >= tmp.start) {
- alloc.start = alignf(alignf_data, &avail, size, align);
- alloc.end = alloc.start + size - 1;
- if (resource_contains(&avail, &alloc)) {
- new->start = alloc.start;
- new->end = alloc.end;
- return 0;
- }
- }
-
- if (!this || this->start == root->start)
- break;
-
- tmp.end = this->start - 1;
- this = find_sibling_prev(root, this);
- }
- return -EBUSY;
-}
-
-/*
- * Find empty slot in the resource tree given range and alignment.
- * This version allocates from the beginning of the root resource first.
*/
static int find_resource(struct resource *root, struct resource *new,
resource_size_t size, resource_size_t min,
struct resource *this = root->child;
struct resource tmp = *new, avail, alloc;
+ tmp.flags = new->flags;
tmp.start = root->start;
/*
- * Skip past an allocated resource that starts at 0, since the
- * assignment of this->start - 1 to tmp->end below would cause an
- * underflow.
+ * Skip past an allocated resource that starts at 0, since the assignment
+ * of this->start - 1 to tmp->end below would cause an underflow.
*/
if (this && this->start == 0) {
tmp.start = this->end + 1;
this = this->sibling;
}
- for (;;) {
+ for(;;) {
if (this)
tmp.end = this->start - 1;
else
tmp.end = root->end;
resource_clip(&tmp, min, max);
+ arch_remove_reservations(&tmp);
/* Check for overflow after ALIGN() */
avail = *new;
return 0;
}
}
-
if (!this)
break;
-
tmp.start = this->end + 1;
this = this->sibling;
}
alignf = simple_align_resource;
write_lock(&resource_lock);
- if (resource_alloc_from_bottom)
- err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
- else
- err = find_resource_from_top(root, new, size, min, max, align, alignf, alignf_data);
+ err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
if (err >= 0 && __request_resource(root, new))
err = -EBUSY;
write_unlock(&resource_lock);
#endif /* CONFIG_CGROUP_SCHED */
-static u64 irq_time_cpu(int cpu);
-static void sched_irq_time_avg_update(struct rq *rq, u64 irq_time);
+static void update_rq_clock_task(struct rq *rq, s64 delta);
-inline void update_rq_clock(struct rq *rq)
+static void update_rq_clock(struct rq *rq)
{
- if (!rq->skip_clock_update) {
- int cpu = cpu_of(rq);
- u64 irq_time;
+ s64 delta;
- rq->clock = sched_clock_cpu(cpu);
- irq_time = irq_time_cpu(cpu);
- if (rq->clock - irq_time > rq->clock_task)
- rq->clock_task = rq->clock - irq_time;
+ if (rq->skip_clock_update)
+ return;
- sched_irq_time_avg_update(rq, irq_time);
- }
+ delta = sched_clock_cpu(cpu_of(rq)) - rq->clock;
+ rq->clock += delta;
+ update_rq_clock_task(rq, delta);
}
/*
* They are read and saved off onto struct rq in update_rq_clock().
* This may result in other CPU reading this CPU's irq time and can
* race with irq/account_system_vtime on this CPU. We would either get old
- * or new value (or semi updated value on 32 bit) with a side effect of
- * accounting a slice of irq time to wrong task when irq is in progress
- * while we read rq->clock. That is a worthy compromise in place of having
- * locks on each irq in account_system_time.
+ * or new value with a side effect of accounting a slice of irq time to wrong
+ * task when irq is in progress while we read rq->clock. That is a worthy
+ * compromise in place of having locks on each irq in account_system_time.
*/
static DEFINE_PER_CPU(u64, cpu_hardirq_time);
static DEFINE_PER_CPU(u64, cpu_softirq_time);
sched_clock_irqtime = 0;
}
-static u64 irq_time_cpu(int cpu)
+#ifndef CONFIG_64BIT
+static DEFINE_PER_CPU(seqcount_t, irq_time_seq);
+
+static inline void irq_time_write_begin(void)
{
- if (!sched_clock_irqtime)
- return 0;
+ __this_cpu_inc(irq_time_seq.sequence);
+ smp_wmb();
+}
+
+static inline void irq_time_write_end(void)
+{
+ smp_wmb();
+ __this_cpu_inc(irq_time_seq.sequence);
+}
+
+static inline u64 irq_time_read(int cpu)
+{
+ u64 irq_time;
+ unsigned seq;
+ do {
+ seq = read_seqcount_begin(&per_cpu(irq_time_seq, cpu));
+ irq_time = per_cpu(cpu_softirq_time, cpu) +
+ per_cpu(cpu_hardirq_time, cpu);
+ } while (read_seqcount_retry(&per_cpu(irq_time_seq, cpu), seq));
+
+ return irq_time;
+}
+#else /* CONFIG_64BIT */
+static inline void irq_time_write_begin(void)
+{
+}
+
+static inline void irq_time_write_end(void)
+{
+}
+
+static inline u64 irq_time_read(int cpu)
+{
return per_cpu(cpu_softirq_time, cpu) + per_cpu(cpu_hardirq_time, cpu);
}
+#endif /* CONFIG_64BIT */
+/*
+ * Called before incrementing preempt_count on {soft,}irq_enter
+ * and before decrementing preempt_count on {soft,}irq_exit.
+ */
void account_system_vtime(struct task_struct *curr)
{
unsigned long flags;
+ s64 delta;
int cpu;
- u64 now, delta;
if (!sched_clock_irqtime)
return;
local_irq_save(flags);
cpu = smp_processor_id();
- now = sched_clock_cpu(cpu);
- delta = now - per_cpu(irq_start_time, cpu);
- per_cpu(irq_start_time, cpu) = now;
+ delta = sched_clock_cpu(cpu) - __this_cpu_read(irq_start_time);
+ __this_cpu_add(irq_start_time, delta);
+
+ irq_time_write_begin();
/*
* We do not account for softirq time from ksoftirqd here.
* We want to continue accounting softirq time to ksoftirqd thread
* that do not consume any time, but still wants to run.
*/
if (hardirq_count())
- per_cpu(cpu_hardirq_time, cpu) += delta;
+ __this_cpu_add(cpu_hardirq_time, delta);
else if (in_serving_softirq() && !(curr->flags & PF_KSOFTIRQD))
- per_cpu(cpu_softirq_time, cpu) += delta;
+ __this_cpu_add(cpu_softirq_time, delta);
+ irq_time_write_end();
local_irq_restore(flags);
}
EXPORT_SYMBOL_GPL(account_system_vtime);
-static void sched_irq_time_avg_update(struct rq *rq, u64 curr_irq_time)
+static void update_rq_clock_task(struct rq *rq, s64 delta)
{
- if (sched_clock_irqtime && sched_feat(NONIRQ_POWER)) {
- u64 delta_irq = curr_irq_time - rq->prev_irq_time;
- rq->prev_irq_time = curr_irq_time;
- sched_rt_avg_update(rq, delta_irq);
- }
+ s64 irq_delta;
+
+ irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time;
+
+ /*
+ * Since irq_time is only updated on {soft,}irq_exit, we might run into
+ * this case when a previous update_rq_clock() happened inside a
+ * {soft,}irq region.
+ *
+ * When this happens, we stop ->clock_task and only update the
+ * prev_irq_time stamp to account for the part that fit, so that a next
+ * update will consume the rest. This ensures ->clock_task is
+ * monotonic.
+ *
+ * It does however cause some slight miss-attribution of {soft,}irq
+ * time, a more accurate solution would be to update the irq_time using
+ * the current rq->clock timestamp, except that would require using
+ * atomic ops.
+ */
+ if (irq_delta > delta)
+ irq_delta = delta;
+
+ rq->prev_irq_time += irq_delta;
+ delta -= irq_delta;
+ rq->clock_task += delta;
+
+ if (irq_delta && sched_feat(NONIRQ_POWER))
+ sched_rt_avg_update(rq, irq_delta);
}
-#else
+#else /* CONFIG_IRQ_TIME_ACCOUNTING */
-static u64 irq_time_cpu(int cpu)
+static void update_rq_clock_task(struct rq *rq, s64 delta)
{
- return 0;
+ rq->clock_task += delta;
}
-static void sched_irq_time_avg_update(struct rq *rq, u64 curr_irq_time) { }
-
-#endif
+#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
#include "sched_idletask.c"
#include "sched_fair.c"
* A queue event has occurred, and we're going to schedule. In
* this case, we can save a useless back to back clock update.
*/
- if (test_tsk_need_resched(rq->curr))
+ if (rq->curr->se.on_rq && test_tsk_need_resched(rq->curr))
rq->skip_clock_update = 1;
}
return delta;
}
+static unsigned long
+calc_load(unsigned long load, unsigned long exp, unsigned long active)
+{
+ load *= exp;
+ load += active * (FIXED_1 - exp);
+ load += 1UL << (FSHIFT - 1);
+ return load >> FSHIFT;
+}
+
#ifdef CONFIG_NO_HZ
/*
* For NO_HZ we delay the active fold to the next LOAD_FREQ update.
return delta;
}
+
+/**
+ * fixed_power_int - compute: x^n, in O(log n) time
+ *
+ * @x: base of the power
+ * @frac_bits: fractional bits of @x
+ * @n: power to raise @x to.
+ *
+ * By exploiting the relation between the definition of the natural power
+ * function: x^n := x*x*...*x (x multiplied by itself for n times), and
+ * the binary encoding of numbers used by computers: n := \Sum n_i * 2^i,
+ * (where: n_i \elem {0, 1}, the binary vector representing n),
+ * we find: x^n := x^(\Sum n_i * 2^i) := \Prod x^(n_i * 2^i), which is
+ * of course trivially computable in O(log_2 n), the length of our binary
+ * vector.
+ */
+static unsigned long
+fixed_power_int(unsigned long x, unsigned int frac_bits, unsigned int n)
+{
+ unsigned long result = 1UL << frac_bits;
+
+ if (n) for (;;) {
+ if (n & 1) {
+ result *= x;
+ result += 1UL << (frac_bits - 1);
+ result >>= frac_bits;
+ }
+ n >>= 1;
+ if (!n)
+ break;
+ x *= x;
+ x += 1UL << (frac_bits - 1);
+ x >>= frac_bits;
+ }
+
+ return result;
+}
+
+/*
+ * a1 = a0 * e + a * (1 - e)
+ *
+ * a2 = a1 * e + a * (1 - e)
+ * = (a0 * e + a * (1 - e)) * e + a * (1 - e)
+ * = a0 * e^2 + a * (1 - e) * (1 + e)
+ *
+ * a3 = a2 * e + a * (1 - e)
+ * = (a0 * e^2 + a * (1 - e) * (1 + e)) * e + a * (1 - e)
+ * = a0 * e^3 + a * (1 - e) * (1 + e + e^2)
+ *
+ * ...
+ *
+ * an = a0 * e^n + a * (1 - e) * (1 + e + ... + e^n-1) [1]
+ * = a0 * e^n + a * (1 - e) * (1 - e^n)/(1 - e)
+ * = a0 * e^n + a * (1 - e^n)
+ *
+ * [1] application of the geometric series:
+ *
+ * n 1 - x^(n+1)
+ * S_n := \Sum x^i = -------------
+ * i=0 1 - x
+ */
+static unsigned long
+calc_load_n(unsigned long load, unsigned long exp,
+ unsigned long active, unsigned int n)
+{
+
+ return calc_load(load, fixed_power_int(exp, FSHIFT, n), active);
+}
+
+/*
+ * NO_HZ can leave us missing all per-cpu ticks calling
+ * calc_load_account_active(), but since an idle CPU folds its delta into
+ * calc_load_tasks_idle per calc_load_account_idle(), all we need to do is fold
+ * in the pending idle delta if our idle period crossed a load cycle boundary.
+ *
+ * Once we've updated the global active value, we need to apply the exponential
+ * weights adjusted to the number of cycles missed.
+ */
+static void calc_global_nohz(unsigned long ticks)
+{
+ long delta, active, n;
+
+ if (time_before(jiffies, calc_load_update))
+ return;
+
+ /*
+ * If we crossed a calc_load_update boundary, make sure to fold
+ * any pending idle changes, the respective CPUs might have
+ * missed the tick driven calc_load_account_active() update
+ * due to NO_HZ.
+ */
+ delta = calc_load_fold_idle();
+ if (delta)
+ atomic_long_add(delta, &calc_load_tasks);
+
+ /*
+ * If we were idle for multiple load cycles, apply them.
+ */
+ if (ticks >= LOAD_FREQ) {
+ n = ticks / LOAD_FREQ;
+
+ active = atomic_long_read(&calc_load_tasks);
+ active = active > 0 ? active * FIXED_1 : 0;
+
+ avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
+ avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
+ avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
+
+ calc_load_update += n * LOAD_FREQ;
+ }
+
+ /*
+ * Its possible the remainder of the above division also crosses
+ * a LOAD_FREQ period, the regular check in calc_global_load()
+ * which comes after this will take care of that.
+ *
+ * Consider us being 11 ticks before a cycle completion, and us
+ * sleeping for 4*LOAD_FREQ + 22 ticks, then the above code will
+ * age us 4 cycles, and the test in calc_global_load() will
+ * pick up the final one.
+ */
+}
#else
static void calc_load_account_idle(struct rq *this_rq)
{
{
return 0;
}
+
+static void calc_global_nohz(unsigned long ticks)
+{
+}
#endif
/**
loads[2] = (avenrun[2] + offset) << shift;
}
-static unsigned long
-calc_load(unsigned long load, unsigned long exp, unsigned long active)
-{
- load *= exp;
- load += active * (FIXED_1 - exp);
- return load >> FSHIFT;
-}
-
/*
* calc_load - update the avenrun load estimates 10 ticks after the
* CPUs have updated calc_load_tasks.
*/
-void calc_global_load(void)
+void calc_global_load(unsigned long ticks)
{
- unsigned long upd = calc_load_update + 10;
long active;
- if (time_before(jiffies, upd))
+ calc_global_nohz(ticks);
+
+ if (time_before(jiffies, calc_load_update + 10))
return;
active = atomic_long_read(&calc_load_tasks);
{
if (prev->se.on_rq)
update_rq_clock(rq);
- rq->skip_clock_update = 0;
prev->sched_class->put_prev_task(rq, prev);
}
hrtick_clear(rq);
raw_spin_lock_irq(&rq->lock);
- clear_tsk_need_resched(prev);
switch_count = &prev->nivcsw;
if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
put_prev_task(rq, prev);
next = pick_next_task(rq);
+ clear_tsk_need_resched(prev);
+ rq->skip_clock_update = 0;
if (likely(prev != next)) {
sched_info_switch(prev, next);
return ret;
}
+#ifdef CONFIG_IA64
+#define TASKSTATS_NEEDS_PADDING 1
+#endif
+
static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
{
struct nlattr *na, *ret;
int aggr;
- /* If we don't pad, we end up with alignment on a 4 byte boundary.
- * This causes lots of runtime warnings on systems requiring 8 byte
- * alignment */
- u32 pids[2] = { pid, 0 };
- int pid_size = ALIGN(sizeof(pid), sizeof(long));
-
aggr = (type == TASKSTATS_TYPE_PID)
? TASKSTATS_TYPE_AGGR_PID
: TASKSTATS_TYPE_AGGR_TGID;
+ /*
+ * The taskstats structure is internally aligned on 8 byte
+ * boundaries but the layout of the aggregrate reply, with
+ * two NLA headers and the pid (each 4 bytes), actually
+ * force the entire structure to be unaligned. This causes
+ * the kernel to issue unaligned access warnings on some
+ * architectures like ia64. Unfortunately, some software out there
+ * doesn't properly unroll the NLA packet and assumes that the start
+ * of the taskstats structure will always be 20 bytes from the start
+ * of the netlink payload. Aligning the start of the taskstats
+ * structure breaks this software, which we don't want. So, for now
+ * the alignment only happens on architectures that require it
+ * and those users will have to update to fixed versions of those
+ * packages. Space is reserved in the packet only when needed.
+ * This ifdef should be removed in several years e.g. 2012 once
+ * we can be confident that fixed versions are installed on most
+ * systems. We add the padding before the aggregate since the
+ * aggregate is already a defined type.
+ */
+#ifdef TASKSTATS_NEEDS_PADDING
+ if (nla_put(skb, TASKSTATS_TYPE_NULL, 0, NULL) < 0)
+ goto err;
+#endif
na = nla_nest_start(skb, aggr);
if (!na)
goto err;
- if (nla_put(skb, type, pid_size, pids) < 0)
+
+ if (nla_put(skb, type, sizeof(pid), &pid) < 0)
goto err;
ret = nla_reserve(skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats));
if (!ret)
return rc;
}
+static size_t taskstats_packet_size(void)
+{
+ size_t size;
+
+ size = nla_total_size(sizeof(u32)) +
+ nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
+#ifdef TASKSTATS_NEEDS_PADDING
+ size += nla_total_size(0); /* Padding for alignment */
+#endif
+ return size;
+}
+
static int cmd_attr_pid(struct genl_info *info)
{
struct taskstats *stats;
u32 pid;
int rc;
- size = nla_total_size(sizeof(u32)) +
- nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
+ size = taskstats_packet_size();
rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
if (rc < 0)
u32 tgid;
int rc;
- size = nla_total_size(sizeof(u32)) +
- nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
+ size = taskstats_packet_size();
rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
if (rc < 0)
/*
* Size includes space for nested attributes
*/
- size = nla_total_size(sizeof(u32)) +
- nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
+ size = taskstats_packet_size();
is_thread_group = !!taskstats_tgid_alloc(tsk);
if (is_thread_group) {
struct tvec_base *base = __get_cpu_var(tvec_bases);
unsigned long expires;
+ /*
+ * Pretend that there is no timer pending if the cpu is offline.
+ * Possible pending timers will be migrated later to an active cpu.
+ */
+ if (cpu_is_offline(smp_processor_id()))
+ return now + NEXT_TIMER_MAX_DELTA;
spin_lock(&base->lock);
if (time_before_eq(base->next_timer, base->timer_jiffies))
base->next_timer = __next_timer_interrupt(base);
{
jiffies_64 += ticks;
update_wall_time();
- calc_global_load();
+ calc_global_load(ticks);
}
#ifdef __ARCH_WANT_SYS_ALARM
/* Need to copy one event at a time */
do {
+ /* We need the size of one event, because
+ * rb_advance_reader only advances by one event,
+ * whereas rb_event_ts_length may include the size of
+ * one or two events.
+ * We have already ensured there's enough space if this
+ * is a time extend. */
+ size = rb_event_length(event);
memcpy(bpage->data + pos, rpage->data + rpos, size);
len -= size;
event = rb_reader_event(cpu_buffer);
/* Always keep the time extend and data together */
size = rb_event_ts_length(event);
- } while (len > size);
+ } while (len >= size);
/* update bpage */
local_set(&bpage->commit, pos);
return count;
}
+static loff_t tracing_seek(struct file *file, loff_t offset, int origin)
+{
+ if (file->f_mode & FMODE_READ)
+ return seq_lseek(file, offset, origin);
+ else
+ return 0;
+}
+
static const struct file_operations tracing_fops = {
.open = tracing_open,
.read = seq_read,
.write = tracing_write_stub,
- .llseek = seq_lseek,
+ .llseek = tracing_seek,
.release = tracing_release,
};
spin_lock_irq(&uidhash_lock);
up = uid_hash_find(uid, hashent);
if (up) {
+ put_user_ns(ns);
key_put(new->uid_keyring);
key_put(new->session_keyring);
kmem_cache_free(uid_cachep, new);
goto out_save;
}
- printk(KERN_ERR "NMI watchdog failed to create perf event on cpu%i: %p\n", cpu, event);
+ printk(KERN_ERR "NMI watchdog disabled for cpu%i: unable to create perf event: %ld\n",
+ cpu, PTR_ERR(event));
return PTR_ERR(event);
/* success path */
/* Successfully isolated */
del_page_from_lru_list(zone, page, page_lru(page));
list_add(&page->lru, migratelist);
- mem_cgroup_del_lru(page);
cc->nr_migratepages++;
/* Avoid isolating too much */
rcu_read_lock();
p = rcu_dereference(mm->owner);
- VM_BUG_ON(!p);
/*
- * because we don't have task_lock(), "p" can exit while
- * we're here. In that case, "mem" can point to root
- * cgroup but never be NULL. (and task_struct itself is freed
- * by RCU, cgroup itself is RCU safe.) Then, we have small
- * risk here to get wrong cgroup. But such kind of mis-account
- * by race always happens because we don't have cgroup_mutex().
- * It's overkill and we allow that small race, here.
+ * Because we don't have task_lock(), "p" can exit.
+ * In that case, "mem" can point to root or p can be NULL with
+ * race with swapoff. Then, we have small risk of mis-accouning.
+ * But such kind of mis-account by race always happens because
+ * we don't have cgroup_mutex(). It's overkill and we allo that
+ * small race, here.
+ * (*) swapoff at el will charge against mm-struct not against
+ * task-struct. So, mm->owner can be NULL.
*/
mem = mem_cgroup_from_task(p);
- VM_BUG_ON(!mem);
- if (mem_cgroup_is_root(mem)) {
+ if (!mem || mem_cgroup_is_root(mem)) {
rcu_read_unlock();
goto done;
}
#include <linux/hugetlb.h>
#include <linux/gfp.h>
+#include <asm/tlbflush.h>
+
#include "internal.h"
#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
* Copyright (c) 2000-2003 David McCullough <davidm@snapgear.com>
* Copyright (c) 2000-2001 D Jeff Dionne <jeff@uClinux.org>
* Copyright (c) 2002 Greg Ungerer <gerg@snapgear.com>
- * Copyright (c) 2007-2009 Paul Mundt <lethal@linux-sh.org>
+ * Copyright (c) 2007-2010 Paul Mundt <lethal@linux-sh.org>
*/
#include <linux/module.h>
{
return vmalloc(size);
}
+EXPORT_SYMBOL(vmalloc_node);
/**
* vzalloc_node - allocate memory on a specific node with zero fill
{
}
+/**
+ * alloc_vm_area - allocate a range of kernel address space
+ * @size: size of the area
+ *
+ * Returns: NULL on failure, vm_struct on success
+ *
+ * This function reserves a range of kernel address space, and
+ * allocates pagetables to map that range. No actual mappings
+ * are created. If the kernel address space is not shared
+ * between processes, it syncs the pagetable across all
+ * processes.
+ */
+struct vm_struct *alloc_vm_area(size_t size)
+{
+ BUG();
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(alloc_vm_area);
+
+void free_vm_area(struct vm_struct *area)
+{
+ BUG();
+}
+EXPORT_SYMBOL_GPL(free_vm_area);
+
int vm_insert_page(struct vm_area_struct *vma, unsigned long addr,
struct page *page)
{
break; /* We've done our duty */
}
trace_wbc_balance_dirty_wait(&wbc, bdi);
- __set_current_state(TASK_INTERRUPTIBLE);
+ __set_current_state(TASK_UNINTERRUPTIBLE);
io_schedule_timeout(pause);
/*
/* we're done parsing the input, undefine BUG macro and dump config */
#undef PCPU_SETUP_BUG_ON
- pcpu_dump_alloc_info(KERN_INFO, ai);
+ pcpu_dump_alloc_info(KERN_DEBUG, ai);
pcpu_nr_groups = ai->nr_groups;
pcpu_group_offsets = group_offsets;
d->state = BT_OPEN;
d->flags = 0;
d->mscex = 0;
+ d->sec_level = BT_SECURITY_LOW;
d->mtu = RFCOMM_DEFAULT_MTU;
d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
ip6h = ipv6_hdr(skb);
*(__force __be32 *)ip6h = htonl(0x60000000);
- ip6h->payload_len = 8 + sizeof(*mldq);
+ ip6h->payload_len = htons(8 + sizeof(*mldq));
ip6h->nexthdr = IPPROTO_HOPOPTS;
ip6h->hop_limit = 1;
ipv6_addr_set(&ip6h->saddr, 0, 0, 0, 0);
struct net_bridge_port *port,
struct sk_buff *skb)
{
- struct sk_buff *skb2 = skb;
+ struct sk_buff *skb2;
struct ipv6hdr *ip6h;
struct icmp6hdr *icmp6h;
u8 nexthdr;
if (!skb2)
return -ENOMEM;
+ err = -EINVAL;
+ if (!pskb_may_pull(skb2, offset + sizeof(struct icmp6hdr)))
+ goto out;
+
len -= offset - skb_network_offset(skb2);
__skb_pull(skb2, offset);
skb_reset_transport_header(skb2);
- err = -EINVAL;
- if (!pskb_may_pull(skb2, sizeof(*icmp6h)))
- goto out;
-
icmp6h = icmp6_hdr(skb2);
switch (icmp6h->icmp6_type) {
switch (icmp6h->icmp6_type) {
case ICMPV6_MGM_REPORT:
{
- struct mld_msg *mld = (struct mld_msg *)icmp6h;
+ struct mld_msg *mld;
+ if (!pskb_may_pull(skb2, sizeof(*mld))) {
+ err = -EINVAL;
+ goto out;
+ }
+ mld = (struct mld_msg *)skb_transport_header(skb2);
BR_INPUT_SKB_CB(skb2)->mrouters_only = 1;
err = br_ip6_multicast_add_group(br, port, &mld->mld_mca);
break;
break;
case ICMPV6_MGM_REDUCTION:
{
- struct mld_msg *mld = (struct mld_msg *)icmp6h;
+ struct mld_msg *mld;
+ if (!pskb_may_pull(skb2, sizeof(*mld))) {
+ err = -EINVAL;
+ goto out;
+ }
+ mld = (struct mld_msg *)skb_transport_header(skb2);
br_ip6_multicast_leave_group(br, port, &mld->mld_mca);
}
}
out:
- __skb_push(skb2, offset);
- if (skb2 != skb)
- kfree_skb(skb2);
+ kfree_skb(skb2);
return err;
}
#endif
llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr);
+ skb_reset_mac_header(skb);
+
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
dev_queue_xmit);
}
struct list_head tx_ops;
unsigned long dropped_usr_msgs;
struct proc_dir_entry *bcm_proc_read;
- char procname [20]; /* pointer printed in ASCII with \0 */
+ char procname [32]; /* inode number in decimal with \0 */
};
static inline struct bcm_sock *bcm_sk(const struct sock *sk)
if (proc_dir) {
/* unique socket address as filename */
- sprintf(bo->procname, "%p", sock);
+ sprintf(bo->procname, "%lu", sock_i_ino(sk));
bo->bcm_proc_read = proc_create_data(bo->procname, 0644,
proc_dir,
&bcm_proc_fops, sk);
int ceph_msgr_init(void)
{
ceph_msgr_wq = create_workqueue("ceph-msgr");
- if (IS_ERR(ceph_msgr_wq)) {
- int ret = PTR_ERR(ceph_msgr_wq);
- pr_err("msgr_init failed to create workqueue: %d\n", ret);
- ceph_msgr_wq = NULL;
- return ret;
+ if (!ceph_msgr_wq) {
+ pr_err("msgr_init failed to create workqueue\n");
+ return -ENOMEM;
}
return 0;
}
* build a vector of user pages
*/
struct page **ceph_get_direct_page_vector(const char __user *data,
- int num_pages)
+ int num_pages, bool write_page)
{
struct page **pages;
int rc;
down_read(¤t->mm->mmap_sem);
rc = get_user_pages(current, current->mm, (unsigned long)data,
- num_pages, 0, 0, pages, NULL);
+ num_pages, write_page, 0, pages, NULL);
up_read(¤t->mm->mmap_sem);
- if (rc < 0)
+ if (rc < num_pages)
goto fail;
return pages;
fail:
- kfree(pages);
+ ceph_put_page_vector(pages, rc > 0 ? rc : 0, false);
return ERR_PTR(rc);
}
EXPORT_SYMBOL(ceph_get_direct_page_vector);
-void ceph_put_page_vector(struct page **pages, int num_pages)
+void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty)
{
int i;
- for (i = 0; i < num_pages; i++)
+ for (i = 0; i < num_pages; i++) {
+ if (dirty)
+ set_page_dirty_lock(pages[i]);
put_page(pages[i]);
+ }
kfree(pages);
}
EXPORT_SYMBOL(ceph_put_page_vector);
{
int ret = 0;
- if (rule->iifindex && (rule->iifindex != fl->iif) &&
- !(fl->flags & FLOWI_FLAG_MATCH_ANY_IIF))
+ if (rule->iifindex && (rule->iifindex != fl->iif))
goto out;
if (rule->oifindex && (rule->oifindex != fl->oif))
#endif
}
+/*
+ * caches using SLAB_DESTROY_BY_RCU should let .next pointer from nulls nodes
+ * un-modified. Special care is taken when initializing object to zero.
+ */
+static inline void sk_prot_clear_nulls(struct sock *sk, int size)
+{
+ if (offsetof(struct sock, sk_node.next) != 0)
+ memset(sk, 0, offsetof(struct sock, sk_node.next));
+ memset(&sk->sk_node.pprev, 0,
+ size - offsetof(struct sock, sk_node.pprev));
+}
+
+void sk_prot_clear_portaddr_nulls(struct sock *sk, int size)
+{
+ unsigned long nulls1, nulls2;
+
+ nulls1 = offsetof(struct sock, __sk_common.skc_node.next);
+ nulls2 = offsetof(struct sock, __sk_common.skc_portaddr_node.next);
+ if (nulls1 > nulls2)
+ swap(nulls1, nulls2);
+
+ if (nulls1 != 0)
+ memset((char *)sk, 0, nulls1);
+ memset((char *)sk + nulls1 + sizeof(void *), 0,
+ nulls2 - nulls1 - sizeof(void *));
+ memset((char *)sk + nulls2 + sizeof(void *), 0,
+ size - nulls2 - sizeof(void *));
+}
+EXPORT_SYMBOL(sk_prot_clear_portaddr_nulls);
+
static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,
int family)
{
if (!sk)
return sk;
if (priority & __GFP_ZERO) {
- /*
- * caches using SLAB_DESTROY_BY_RCU should let
- * sk_node.next un-modified. Special care is taken
- * when initializing object to zero.
- */
- if (offsetof(struct sock, sk_node.next) != 0)
- memset(sk, 0, offsetof(struct sock, sk_node.next));
- memset(&sk->sk_node.pprev, 0,
- prot->obj_size - offsetof(struct sock,
- sk_node.pprev));
+ if (prot->clear_sk)
+ prot->clear_sk(sk, prot->obj_size);
+ else
+ sk_prot_clear_nulls(sk, prot->obj_size);
}
- }
- else
+ } else
sk = kmalloc(prot->obj_size, priority);
if (sk != NULL) {
.daddr = addr
}
},
- .flags = FLOWI_FLAG_MATCH_ANY_IIF
};
struct fib_result res = { 0 };
struct net_device *dev = NULL;
+ struct fib_table *local_table;
+
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ res.r = NULL;
+#endif
rcu_read_lock();
- if (fib_lookup(net, &fl, &res)) {
+ local_table = fib_get_table(net, RT_TABLE_LOCAL);
+ if (!local_table ||
+ fib_table_lookup(local_table, &fl, &res, FIB_LOOKUP_NOREF)) {
rcu_read_unlock();
return NULL;
}
goto out;
/* RACE: Check return value of inet_select_addr instead. */
- if (rcu_dereference(dev_out->ip_ptr) == NULL)
- goto out; /* Wrong error code */
-
+ if (!(dev_out->flags & IFF_UP) || !__in_dev_get_rcu(dev_out)) {
+ err = -ENETUNREACH;
+ goto out;
+ }
if (ipv4_is_local_multicast(oldflp->fl4_dst) ||
ipv4_is_lbcast(oldflp->fl4_dst)) {
if (!fl.fl4_src)
}
if (res.type == RTN_LOCAL) {
- if (!fl.fl4_src)
- fl.fl4_src = fl.fl4_dst;
+ if (!fl.fl4_src) {
+ if (res.fi->fib_prefsrc)
+ fl.fl4_src = res.fi->fib_prefsrc;
+ else
+ fl.fl4_src = fl.fl4_dst;
+ }
dev_out = net->loopback_dev;
fl.oif = dev_out->ifindex;
res.fi = NULL;
get_req:
req = icsk->icsk_accept_queue.listen_opt->syn_table[st->sbucket];
}
- sk = sk_next(st->syn_wait_sk);
+ sk = sk_nulls_next(st->syn_wait_sk);
st->state = TCP_SEQ_STATE_LISTENING;
read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
} else {
if (reqsk_queue_len(&icsk->icsk_accept_queue))
goto start_req;
read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
- sk = sk_next(sk);
+ sk = sk_nulls_next(sk);
}
get_sk:
sk_nulls_for_each_from(sk, node) {
.compat_setsockopt = compat_udp_setsockopt,
.compat_getsockopt = compat_udp_getsockopt,
#endif
+ .clear_sk = sk_prot_clear_portaddr_nulls,
};
EXPORT_SYMBOL(udp_prot);
.compat_setsockopt = compat_udp_setsockopt,
.compat_getsockopt = compat_udp_getsockopt,
#endif
+ .clear_sk = sk_prot_clear_portaddr_nulls,
};
EXPORT_SYMBOL(udplite_prot);
ASSERT_RTNL();
- rt6_ifdown(net, dev);
+ /* Flush routes if device is being removed or it is not loopback */
+ if (how || !(dev->flags & IFF_LOOPBACK))
+ rt6_ifdown(net, dev);
neigh_ifdown(&nd_tbl, dev);
idev = __in6_dev_get(dev);
#include <net/checksum.h>
#include <linux/mroute6.h>
-static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
+int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
int __ip6_local_out(struct sk_buff *skb)
{
return -EINVAL;
}
-static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
-{
- struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
-
- return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ?
- skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
-}
-
static int ip6_finish_output(struct sk_buff *skb)
{
if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
return offset;
}
-static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
+int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
{
struct sk_buff *frag;
struct rt6_info *rt = (struct rt6_info*)skb_dst(skb);
{
struct rt6_info *rt, *nrt;
int allfrag = 0;
-
+again:
rt = rt6_lookup(net, daddr, saddr, ifindex, 0);
if (rt == NULL)
return;
+ if (rt6_check_expired(rt)) {
+ ip6_del_rt(rt);
+ goto again;
+ }
+
if (pmtu >= dst_mtu(&rt->dst))
goto out;
.compat_setsockopt = compat_udpv6_setsockopt,
.compat_getsockopt = compat_udpv6_getsockopt,
#endif
+ .clear_sk = sk_prot_clear_portaddr_nulls,
};
static struct inet_protosw udpv6_protosw = {
.compat_setsockopt = compat_udpv6_setsockopt,
.compat_getsockopt = compat_udpv6_getsockopt,
#endif
+ .clear_sk = sk_prot_clear_portaddr_nulls,
};
static struct inet_protosw udplite6_protosw = {
#include <linux/netfilter_ipv6.h>
#include <net/dst.h>
#include <net/ipv6.h>
+#include <net/ip6_route.h>
#include <net/xfrm.h>
int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
return xfrm_output(skb);
}
+static int __xfrm6_output(struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb_dst(skb);
+ struct xfrm_state *x = dst->xfrm;
+
+ if ((x && x->props.mode == XFRM_MODE_TUNNEL) &&
+ ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
+ dst_allfrag(skb_dst(skb)))) {
+ return ip6_fragment(skb, xfrm6_output_finish);
+ }
+ return xfrm6_output_finish(skb);
+}
+
int xfrm6_output(struct sk_buff *skb)
{
return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
- skb_dst(skb)->dev, xfrm6_output_finish);
+ skb_dst(skb)->dev, __xfrm6_output);
}
switch (optname) {
case IRLMP_ENUMDEVICES:
+
+ /* Offset to first device entry */
+ offset = sizeof(struct irda_device_list) -
+ sizeof(struct irda_device_info);
+
+ if (len < offset) {
+ err = -EINVAL;
+ goto out;
+ }
+
/* Ask lmp for the current discovery log */
discoveries = irlmp_get_discoveries(&list.len, self->mask.word,
self->nslots);
}
/* Write total list length back to client */
- if (copy_to_user(optval, &list,
- sizeof(struct irda_device_list) -
- sizeof(struct irda_device_info)))
+ if (copy_to_user(optval, &list, offset))
err = -EFAULT;
- /* Offset to first device entry */
- offset = sizeof(struct irda_device_list) -
- sizeof(struct irda_device_info);
-
/* Copy the list itself - watch for overflow */
if (list.len > 2048) {
err = -EINVAL;
mutex_lock(&sdata->u.ibss.mtx);
+ if (!sdata->u.ibss.ssid_len)
+ goto mgmt_out; /* not ready to merge yet */
+
switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_PROBE_REQ:
ieee80211_rx_mgmt_probe_req(sdata, mgmt, skb->len);
break;
}
+ mgmt_out:
mutex_unlock(&sdata->u.ibss.mtx);
}
fwd_skb = skb_copy(skb, GFP_ATOMIC);
- if (!fwd_skb && net_ratelimit())
+ if (!fwd_skb && net_ratelimit()) {
printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
sdata->name);
+ goto out;
+ }
fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
}
}
+ out:
if (is_multicast_ether_addr(hdr->addr1) ||
sdata->dev->flags & IFF_PROMISC)
return RX_CONTINUE;
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_work *wk;
+ bool cleanup = false;
mutex_lock(&local->mtx);
list_for_each_entry(wk, &local->work_list, list) {
if (wk->sdata != sdata)
continue;
+ cleanup = true;
wk->type = IEEE80211_WORK_ABORT;
wk->started = true;
wk->timeout = jiffies;
mutex_unlock(&local->mtx);
/* run cleanups etc. */
- ieee80211_work_work(&local->work_work);
+ if (cleanup)
+ ieee80211_work_work(&local->work_work);
mutex_lock(&local->mtx);
list_for_each_entry(wk, &local->work_list, list) {
/* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */
d = q->next[q->tail];
q->next[q->tail] = q->next[d];
- q->allot[q->next[d]] += q->quantum;
skb = q->qs[d].prev;
len = qdisc_pkt_len(skb);
__skb_unlink(skb, &q->qs[d]);
sfq_inc(q, x);
if (q->qs[x].qlen == 1) { /* The flow is new */
if (q->tail == SFQ_DEPTH) { /* It is the first flow */
- q->tail = x;
q->next[x] = x;
- q->allot[x] = q->quantum;
} else {
q->next[x] = q->next[q->tail];
q->next[q->tail] = x;
- q->tail = x;
}
+ q->tail = x;
+ q->allot[x] = q->quantum;
}
if (++sch->q.qlen <= q->limit) {
sch->bstats.bytes += qdisc_pkt_len(skb);
{
struct sfq_sched_data *q = qdisc_priv(sch);
struct sk_buff *skb;
- sfq_index a, old_a;
+ sfq_index a, next_a;
/* No active slots */
if (q->tail == SFQ_DEPTH)
return NULL;
- a = old_a = q->next[q->tail];
+ a = q->next[q->tail];
/* Grab packet */
skb = __skb_dequeue(&q->qs[a]);
/* Is the slot empty? */
if (q->qs[a].qlen == 0) {
q->ht[q->hash[a]] = SFQ_DEPTH;
- a = q->next[a];
- if (a == old_a) {
+ next_a = q->next[a];
+ if (a == next_a) {
q->tail = SFQ_DEPTH;
return skb;
}
- q->next[q->tail] = a;
- q->allot[a] += q->quantum;
+ q->next[q->tail] = next_a;
} else if ((q->allot[a] -= qdisc_pkt_len(skb)) <= 0) {
- q->tail = a;
- a = q->next[a];
q->allot[a] += q->quantum;
+ q->tail = a;
}
return skb;
}
if (copy_to_user(optval, &val, len))
return -EFAULT;
- return -ENOTSUPP;
+ return 0;
}
/*
}
EXPORT_SYMBOL_GPL(xdr_write_pages);
+static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov,
+ __be32 *p, unsigned int len)
+{
+ if (len > iov->iov_len)
+ len = iov->iov_len;
+ if (p == NULL)
+ p = (__be32*)iov->iov_base;
+ xdr->p = p;
+ xdr->end = (__be32*)(iov->iov_base + len);
+ xdr->iov = iov;
+ xdr->page_ptr = NULL;
+}
+
+static int xdr_set_page_base(struct xdr_stream *xdr,
+ unsigned int base, unsigned int len)
+{
+ unsigned int pgnr;
+ unsigned int maxlen;
+ unsigned int pgoff;
+ unsigned int pgend;
+ void *kaddr;
+
+ maxlen = xdr->buf->page_len;
+ if (base >= maxlen)
+ return -EINVAL;
+ maxlen -= base;
+ if (len > maxlen)
+ len = maxlen;
+
+ base += xdr->buf->page_base;
+
+ pgnr = base >> PAGE_SHIFT;
+ xdr->page_ptr = &xdr->buf->pages[pgnr];
+ kaddr = page_address(*xdr->page_ptr);
+
+ pgoff = base & ~PAGE_MASK;
+ xdr->p = (__be32*)(kaddr + pgoff);
+
+ pgend = pgoff + len;
+ if (pgend > PAGE_SIZE)
+ pgend = PAGE_SIZE;
+ xdr->end = (__be32*)(kaddr + pgend);
+ xdr->iov = NULL;
+ return 0;
+}
+
+static void xdr_set_next_page(struct xdr_stream *xdr)
+{
+ unsigned int newbase;
+
+ newbase = (1 + xdr->page_ptr - xdr->buf->pages) << PAGE_SHIFT;
+ newbase -= xdr->buf->page_base;
+
+ if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0)
+ xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len);
+}
+
+static bool xdr_set_next_buffer(struct xdr_stream *xdr)
+{
+ if (xdr->page_ptr != NULL)
+ xdr_set_next_page(xdr);
+ else if (xdr->iov == xdr->buf->head) {
+ if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0)
+ xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len);
+ }
+ return xdr->p != xdr->end;
+}
+
/**
* xdr_init_decode - Initialize an xdr_stream for decoding data.
* @xdr: pointer to xdr_stream struct
*/
void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
{
- struct kvec *iov = buf->head;
- unsigned int len = iov->iov_len;
-
- if (len > buf->len)
- len = buf->len;
xdr->buf = buf;
- xdr->iov = iov;
- xdr->p = p;
- xdr->end = (__be32 *)((char *)iov->iov_base + len);
+ xdr->scratch.iov_base = NULL;
+ xdr->scratch.iov_len = 0;
+ if (buf->head[0].iov_len != 0)
+ xdr_set_iov(xdr, buf->head, p, buf->len);
+ else if (buf->page_len != 0)
+ xdr_set_page_base(xdr, 0, buf->len);
}
EXPORT_SYMBOL_GPL(xdr_init_decode);
-/**
- * xdr_inline_peek - Allow read-ahead in the XDR data stream
- * @xdr: pointer to xdr_stream struct
- * @nbytes: number of bytes of data to decode
- *
- * Check if the input buffer is long enough to enable us to decode
- * 'nbytes' more bytes of data starting at the current position.
- * If so return the current pointer without updating the current
- * pointer position.
- */
-__be32 * xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes)
+static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
{
__be32 *p = xdr->p;
__be32 *q = p + XDR_QUADLEN(nbytes);
if (unlikely(q > xdr->end || q < p))
return NULL;
+ xdr->p = q;
return p;
}
-EXPORT_SYMBOL_GPL(xdr_inline_peek);
/**
- * xdr_inline_decode - Retrieve non-page XDR data to decode
+ * xdr_set_scratch_buffer - Attach a scratch buffer for decoding data.
+ * @xdr: pointer to xdr_stream struct
+ * @buf: pointer to an empty buffer
+ * @buflen: size of 'buf'
+ *
+ * The scratch buffer is used when decoding from an array of pages.
+ * If an xdr_inline_decode() call spans across page boundaries, then
+ * we copy the data into the scratch buffer in order to allow linear
+ * access.
+ */
+void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen)
+{
+ xdr->scratch.iov_base = buf;
+ xdr->scratch.iov_len = buflen;
+}
+EXPORT_SYMBOL_GPL(xdr_set_scratch_buffer);
+
+static __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes)
+{
+ __be32 *p;
+ void *cpdest = xdr->scratch.iov_base;
+ size_t cplen = (char *)xdr->end - (char *)xdr->p;
+
+ if (nbytes > xdr->scratch.iov_len)
+ return NULL;
+ memcpy(cpdest, xdr->p, cplen);
+ cpdest += cplen;
+ nbytes -= cplen;
+ if (!xdr_set_next_buffer(xdr))
+ return NULL;
+ p = __xdr_inline_decode(xdr, nbytes);
+ if (p == NULL)
+ return NULL;
+ memcpy(cpdest, p, nbytes);
+ return xdr->scratch.iov_base;
+}
+
+/**
+ * xdr_inline_decode - Retrieve XDR data to decode
* @xdr: pointer to xdr_stream struct
* @nbytes: number of bytes of data to decode
*
*/
__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
{
- __be32 *p = xdr->p;
- __be32 *q = p + XDR_QUADLEN(nbytes);
+ __be32 *p;
- if (unlikely(q > xdr->end || q < p))
+ if (nbytes == 0)
+ return xdr->p;
+ if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr))
return NULL;
- xdr->p = q;
- return p;
+ p = __xdr_inline_decode(xdr, nbytes);
+ if (p != NULL)
+ return p;
+ return xdr_copy_to_scratch(xdr, nbytes);
}
EXPORT_SYMBOL_GPL(xdr_inline_decode);
*/
void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
{
- char * kaddr = page_address(xdr->buf->pages[0]);
xdr_read_pages(xdr, len);
/*
* Position current pointer at beginning of tail, and
* set remaining message length.
*/
- if (len > PAGE_CACHE_SIZE - xdr->buf->page_base)
- len = PAGE_CACHE_SIZE - xdr->buf->page_base;
- xdr->p = (__be32 *)(kaddr + xdr->buf->page_base);
- xdr->end = (__be32 *)((char *)xdr->p + len);
+ xdr_set_page_base(xdr, 0, len);
}
EXPORT_SYMBOL_GPL(xdr_enter_page);
}
if (current_entry->prompt && current_entry != &rootmenu)
prop_warn(prop, "prompt redefined");
+
+ /* Apply all upper menus' visibilities to actual prompts. */
+ if(type == P_PROMPT) {
+ struct menu *menu = current_entry;
+
+ while ((menu = menu->parent) != NULL) {
+ if (!menu->visibility)
+ continue;
+ prop->visible.expr
+ = expr_alloc_and(prop->visible.expr,
+ menu->visibility);
+ }
+ }
+
current_entry->prompt = prop;
}
prop->text = prompt;
static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
{
- rp->r_info = ELF_R_INFO(sym, type);
+ rp->r_info = _w(ELF_R_INFO(sym, type));
}
static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;
-I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \
--extra=+f --c-kinds=-px \
--regex-asm='/^ENTRY\(([^)]*)\).*/\1/' \
- --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/'
+ --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \
+ --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/' \
+ --regex-c++='/^DEFINE_EVENT\(([^,)]*).*/trace_\1/'
all_kconfigs | xargs $1 -a \
--langdef=kconfig --language-force=kconfig \
result = security_filter_rule_init(entry->lsm[lsm_rule].type,
Audit_equal, args,
&entry->lsm[lsm_rule].rule);
+ if (!entry->lsm[lsm_rule].rule)
+ return -EINVAL;
return result;
}
return ret;
link_prealloc_failed:
- up_write(&dest_keyring->sem);
mutex_unlock(&user->cons_lock);
kleave(" = %d [prelink]", ret);
return ret;
struct snd_pcm_hw_rule *new;
unsigned int new_rules = constrs->rules_all + 16;
new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL);
- if (!new)
+ if (!new) {
+ va_end(args);
return -ENOMEM;
+ }
if (constrs->rules) {
memcpy(new, constrs->rules,
constrs->rules_num * sizeof(*c));
c->private = private;
k = 0;
while (1) {
- if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps)))
+ if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps))) {
+ va_end(args);
return -EINVAL;
+ }
c->deps[k++] = dep;
if (dep < 0)
break;
constrs->rules_num++;
va_end(args);
return 0;
-}
+}
EXPORT_SYMBOL(snd_pcm_hw_rule_add);
int i, n;
for (i = 0; i < num_mixer_volumes; i++) {
- if (strcmp(name, mixer_vols[i].name) == 0) {
+ if (strncmp(name, mixer_vols[i].name, 32) == 0) {
if (present)
mixer_vols[i].num = i;
return mixer_vols[i].levels;
}
n = num_mixer_volumes++;
- strcpy(mixer_vols[n].name, name);
+ strncpy(mixer_vols[n].name, name, 32);
if (present)
mixer_vols[n].num = n;
}
EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
+static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name)
+{
+ int idx;
+ for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */
+ if (!_snd_hda_find_mixer_ctl(codec, name, idx))
+ return idx;
+ }
+ return -EBUSY;
+}
+
/**
* snd_hda_ctl_add - Add a control element and assign to the codec
* @codec: HD-audio codec
{ } /* end */
};
-#define SPDIF_MAX_IDX 4 /* 4 instances should be enough to probe */
-
/**
* snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls
* @codec: the HDA codec
struct snd_kcontrol_new *dig_mix;
int idx;
- for (idx = 0; idx < SPDIF_MAX_IDX; idx++) {
- if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch",
- idx))
- break;
- }
- if (idx >= SPDIF_MAX_IDX) {
+ idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch");
+ if (idx < 0) {
printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
return -EBUSY;
}
struct snd_kcontrol_new *dig_mix;
int idx;
- for (idx = 0; idx < SPDIF_MAX_IDX; idx++) {
- if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Capture Switch",
- idx))
- break;
- }
- if (idx >= SPDIF_MAX_IDX) {
+ idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch");
+ if (idx < 0) {
printk(KERN_ERR "hda_codec: too many IEC958 inputs\n");
return -EBUSY;
}
for (; knew->name; knew++) {
struct snd_kcontrol *kctl;
+ int addr = 0, idx = 0;
if (knew->iface == -1) /* skip this codec private value */
continue;
- kctl = snd_ctl_new1(knew, codec);
- if (!kctl)
- return -ENOMEM;
- err = snd_hda_ctl_add(codec, 0, kctl);
- if (err < 0) {
- if (!codec->addr)
- return err;
+ for (;;) {
kctl = snd_ctl_new1(knew, codec);
if (!kctl)
return -ENOMEM;
- kctl->id.device = codec->addr;
+ if (addr > 0)
+ kctl->id.device = addr;
+ if (idx > 0)
+ kctl->id.index = idx;
err = snd_hda_ctl_add(codec, 0, kctl);
- if (err < 0)
+ if (!err)
+ break;
+ /* try first with another device index corresponding to
+ * the codec addr; if it still fails (or it's the
+ * primary codec), then try another control index
+ */
+ if (!addr && codec->addr)
+ addr = codec->addr;
+ else if (!idx && !knew->index) {
+ idx = find_empty_mixer_ctl_idx(codec,
+ knew->name);
+ if (idx <= 0)
+ return err;
+ } else
return err;
}
}
SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB),
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
{
struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
- int i, err;
+ int i, err, type;
+ int type_idx = 0;
hda_nid_t nid;
for (i = 0; i < cfg->num_inputs; i++) {
nid = cfg->inputs[i].pin;
if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
char label[32];
+ type = cfg->inputs[i].type;
+ if (i > 0 && type == cfg->inputs[i - 1].type)
+ type_idx++;
+ else
+ type_idx = 0;
snprintf(label, sizeof(label), "%s Boost",
hda_get_autocfg_input_label(codec, cfg, i));
- err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0,
+ err = add_control(spec, ALC_CTL_WIDGET_VOL, label,
+ type_idx,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
if (err < 0)
return err;
enum {
ALC269_FIXUP_SONY_VAIO,
+ ALC275_FIX_SONY_VAIO_GPIO2,
ALC269_FIXUP_DELL_M101Z,
+ ALC269_FIXUP_SKU_IGNORE,
+ ALC269_FIXUP_ASUS_G73JW,
};
static const struct alc_fixup alc269_fixups[] = {
{}
}
},
+ [ALC275_FIX_SONY_VAIO_GPIO2] = {
+ .verbs = (const struct hda_verb[]) {
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+ { }
+ }
+ },
[ALC269_FIXUP_DELL_M101Z] = {
.verbs = (const struct hda_verb[]) {
/* Enables internal speaker */
{}
}
},
+ [ALC269_FIXUP_SKU_IGNORE] = {
+ .sku = ALC_FIXUP_SKU_IGNORE,
+ },
+ [ALC269_FIXUP_ASUS_G73JW] = {
+ .pins = (const struct alc_pincfg[]) {
+ { 0x17, 0x99130111 }, /* subwoofer */
+ { }
+ }
+ },
};
static struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
+ SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
+ SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
+ SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
+ SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
+ SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
{}
};
alc_auto_parse_customize_define(codec);
- coef = alc_read_coef_idx(codec, 0);
- if ((coef & 0x00f0) == 0x0010) {
- if (codec->bus->pci->subsystem_vendor == 0x1025 &&
- spec->cdefine.platform_type == 1) {
- alc_codec_rename(codec, "ALC271X");
- spec->codec_variant = ALC269_TYPE_ALC271X;
- } else if ((coef & 0xf000) == 0x1000) {
- spec->codec_variant = ALC269_TYPE_ALC270;
- } else if ((coef & 0xf000) == 0x2000) {
- alc_codec_rename(codec, "ALC259");
- spec->codec_variant = ALC269_TYPE_ALC259;
- } else if ((coef & 0xf000) == 0x3000) {
- alc_codec_rename(codec, "ALC258");
- spec->codec_variant = ALC269_TYPE_ALC258;
- } else {
- alc_codec_rename(codec, "ALC269VB");
- spec->codec_variant = ALC269_TYPE_ALC269VB;
- }
- } else
- alc_fix_pll_init(codec, 0x20, 0x04, 15);
-
- alc269_fill_coef(codec);
+ if (codec->vendor_id == 0x10ec0269) {
+ coef = alc_read_coef_idx(codec, 0);
+ if ((coef & 0x00f0) == 0x0010) {
+ if (codec->bus->pci->subsystem_vendor == 0x1025 &&
+ spec->cdefine.platform_type == 1) {
+ alc_codec_rename(codec, "ALC271X");
+ spec->codec_variant = ALC269_TYPE_ALC271X;
+ } else if ((coef & 0xf000) == 0x1000) {
+ spec->codec_variant = ALC269_TYPE_ALC270;
+ } else if ((coef & 0xf000) == 0x2000) {
+ alc_codec_rename(codec, "ALC259");
+ spec->codec_variant = ALC269_TYPE_ALC259;
+ } else if ((coef & 0xf000) == 0x3000) {
+ alc_codec_rename(codec, "ALC258");
+ spec->codec_variant = ALC269_TYPE_ALC258;
+ } else {
+ alc_codec_rename(codec, "ALC269VB");
+ spec->codec_variant = ALC269_TYPE_ALC269VB;
+ }
+ } else
+ alc_fix_pll_init(codec, 0x20, 0x04, 15);
+ alc269_fill_coef(codec);
+ }
board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
alc269_models,
label = hda_get_input_pin_label(codec, nid, 1);
snd_hda_add_imux_item(dimux, label, index, &type_idx);
+ if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1)
+ snd_hda_add_imux_item(imux, label, index, &type_idx);
err = create_elem_capture_vol(codec, nid, label, type_idx,
HDA_INPUT);
if (err < 0)
return err;
}
-
- if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1)
- snd_hda_add_imux_item(imux, label, index, NULL);
}
return 0;
};
struct max98088_priv {
- u8 reg_cache[M98088_REG_CNT];
enum max98088_type devtype;
void *control_data;
struct max98088_pdata *pdata;
static void max98088_sync_cache(struct snd_soc_codec *codec)
{
- struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
int i;
if (!codec->cache_sync)
/* write back cached values if they're writeable and
* different from the hardware default.
*/
- for (i = 1; i < ARRAY_SIZE(max98088->reg_cache); i++) {
+ for (i = 1; i < codec->driver->reg_cache_size; i++) {
if (!max98088_access[i].writable)
continue;
- if (max98088->reg_cache[i] == max98088_reg[i])
+ if (reg_cache[i] == max98088_reg[i])
continue;
- snd_soc_write(codec, i, max98088->reg_cache[i]);
+ snd_soc_write(codec, i, reg_cache[i]);
}
codec->cache_sync = 0;
int ret = 0;
codec->cache_sync = 1;
- memcpy(codec->reg_cache, max98088_reg, sizeof(max98088_reg));
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
if (ret != 0) {
/* codec private data */
struct wm8523_priv {
enum snd_soc_control_type control_type;
- u16 reg_cache[WM8523_REGISTER_COUNT];
struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
unsigned int sysclk;
unsigned int rate_constraint_list[WM8523_NUM_RATES];
enum snd_soc_bias_level level)
{
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
int ret, i;
switch (level) {
/* Sync back default/cached values */
for (i = WM8523_AIF_CTRL1;
i < WM8523_MAX_REGISTER; i++)
- snd_soc_write(codec, i, wm8523->reg_cache[i]);
+ snd_soc_write(codec, i, reg_cache[i]);
msleep(100);
static int wm8523_probe(struct snd_soc_codec *codec)
{
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
int ret, i;
codec->hw_write = (hw_write_t)i2c_master_send;
}
/* Change some default settings - latch VU and enable ZC */
- wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
- wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
+ reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
+ reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
static const u16 wm8580_reg[] = {
0x0121, 0x017e, 0x007d, 0x0014, /*R3*/
0x0121, 0x017e, 0x007d, 0x0194, /*R7*/
- 0x001c, 0x0002, 0x0002, 0x00c2, /*R11*/
+ 0x0010, 0x0002, 0x0002, 0x00c2, /*R11*/
0x0182, 0x0082, 0x000a, 0x0024, /*R15*/
0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/
0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/
/* codec private data */
struct wm8741_priv {
enum snd_soc_control_type control_type;
- u16 reg_cache[WM8741_REGISTER_COUNT];
struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
unsigned int sysclk;
struct snd_pcm_hw_constraint_list *sysclk_constraints;
static int wm8741_probe(struct snd_soc_codec *codec)
{
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
int ret = 0;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
}
/* Change some default settings - latch VU */
- wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
- wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
- wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
- wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
+ reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
+ reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
+ reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
+ reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
snd_soc_add_controls(codec, wm8741_snd_controls,
ARRAY_SIZE(wm8741_snd_controls));
* are using 2 wire for device control, so we cache them instead.
*/
static const u16 wm8753_reg[] = {
- 0x0008, 0x0000, 0x000a, 0x000a,
- 0x0033, 0x0000, 0x0007, 0x00ff,
- 0x00ff, 0x000f, 0x000f, 0x007b,
- 0x0000, 0x0032, 0x0000, 0x00c3,
- 0x00c3, 0x00c0, 0x0000, 0x0000,
+ 0x0000, 0x0008, 0x0000, 0x000a,
+ 0x000a, 0x0033, 0x0000, 0x0007,
+ 0x00ff, 0x00ff, 0x000f, 0x000f,
+ 0x007b, 0x0000, 0x0032, 0x0000,
+ 0x00c3, 0x00c3, 0x00c0, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0055,
- 0x0005, 0x0050, 0x0055, 0x0050,
- 0x0055, 0x0050, 0x0055, 0x0079,
- 0x0079, 0x0079, 0x0079, 0x0079,
0x0000, 0x0000, 0x0000, 0x0000,
- 0x0097, 0x0097, 0x0000, 0x0004,
- 0x0000, 0x0083, 0x0024, 0x01ba,
- 0x0000, 0x0083, 0x0024, 0x01ba,
- 0x0000, 0x0000, 0x0000
+ 0x0055, 0x0005, 0x0050, 0x0055,
+ 0x0050, 0x0055, 0x0050, 0x0055,
+ 0x0079, 0x0079, 0x0079, 0x0079,
+ 0x0079, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0097, 0x0097, 0x0000,
+ 0x0004, 0x0000, 0x0083, 0x0024,
+ 0x01ba, 0x0000, 0x0083, 0x0024,
+ 0x01ba, 0x0000, 0x0000, 0x0000
};
/* codec private data */
enum snd_soc_control_type control_type;
unsigned int sysclk;
unsigned int pcmclk;
- u16 reg_cache[ARRAY_SIZE(wm8753_reg)];
int dai_func;
};
-/*
- * read wm8753 register cache
- */
-static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u16 *cache = codec->reg_cache;
- if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1))
- return -1;
- return cache[reg - 1];
-}
-
-/*
- * write wm8753 register cache
- */
-static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value)
-{
- u16 *cache = codec->reg_cache;
- if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1))
- return;
- cache[reg - 1] = value;
-}
-
-/*
- * write to the WM8753 register space
- */
-static int wm8753_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u8 data[2];
-
- /* data is
- * D15..D9 WM8753 register offset
- * D8...D0 register data
- */
- data[0] = (reg << 1) | ((value >> 8) & 0x0001);
- data[1] = value & 0x00ff;
-
- wm8753_write_reg_cache(codec, reg, value);
- if (codec->hw_write(codec->control_data, data, 2) == 2)
- return 0;
- else
- return -EIO;
-}
-
-#define wm8753_reset(c) wm8753_write(c, WM8753_RESET, 0)
+#define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0)
/*
* WM8753 Controls
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
+ int mode = snd_soc_read(codec, WM8753_IOCTL);
ucontrol->value.integer.value[0] = (mode & 0xc) >> 2;
return 0;
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
+ int mode = snd_soc_read(codec, WM8753_IOCTL);
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
if (pll_id == WM8753_PLL1) {
offset = 0;
enable = 0x10;
- reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xffef;
+ reg = snd_soc_read(codec, WM8753_CLOCK) & 0xffef;
} else {
offset = 4;
enable = 0x8;
- reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfff7;
+ reg = snd_soc_read(codec, WM8753_CLOCK) & 0xfff7;
}
if (!freq_in || !freq_out) {
/* disable PLL */
- wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0026);
- wm8753_write(codec, WM8753_CLOCK, reg);
+ snd_soc_write(codec, WM8753_PLL1CTL1 + offset, 0x0026);
+ snd_soc_write(codec, WM8753_CLOCK, reg);
return 0;
} else {
u16 value = 0;
/* set up N and K PLL divisor ratios */
/* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */
value = (pll_div.n << 5) + ((pll_div.k & 0x3c0000) >> 18);
- wm8753_write(codec, WM8753_PLL1CTL2 + offset, value);
+ snd_soc_write(codec, WM8753_PLL1CTL2 + offset, value);
/* bits 8:0 = PLL_K[17:9] */
value = (pll_div.k & 0x03fe00) >> 9;
- wm8753_write(codec, WM8753_PLL1CTL3 + offset, value);
+ snd_soc_write(codec, WM8753_PLL1CTL3 + offset, value);
/* bits 8:0 = PLL_K[8:0] */
value = pll_div.k & 0x0001ff;
- wm8753_write(codec, WM8753_PLL1CTL4 + offset, value);
+ snd_soc_write(codec, WM8753_PLL1CTL4 + offset, value);
/* set PLL as input and enable */
- wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 |
+ snd_soc_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 |
(pll_div.div2 << 3));
- wm8753_write(codec, WM8753_CLOCK, reg | enable);
+ snd_soc_write(codec, WM8753_CLOCK, reg | enable);
}
return 0;
}
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
- u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01ec;
+ u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01ec;
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
return -EINVAL;
}
- wm8753_write(codec, WM8753_PCM, voice);
+ snd_soc_write(codec, WM8753_PCM, voice);
return 0;
}
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
- u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
- u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
+ u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01f3;
+ u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x017f;
/* bit size */
switch (params_format(params)) {
/* sample rate */
if (params_rate(params) * 384 == wm8753->pcmclk)
srate |= 0x80;
- wm8753_write(codec, WM8753_SRATE1, srate);
+ snd_soc_write(codec, WM8753_SRATE1, srate);
- wm8753_write(codec, WM8753_PCM, voice);
+ snd_soc_write(codec, WM8753_PCM, voice);
return 0;
}
struct snd_soc_codec *codec = codec_dai->codec;
u16 voice, ioctl;
- voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x011f;
- ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x015d;
+ voice = snd_soc_read(codec, WM8753_PCM) & 0x011f;
+ ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x015d;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
return -EINVAL;
}
- wm8753_write(codec, WM8753_PCM, voice);
- wm8753_write(codec, WM8753_IOCTL, ioctl);
+ snd_soc_write(codec, WM8753_PCM, voice);
+ snd_soc_write(codec, WM8753_IOCTL, ioctl);
return 0;
}
switch (div_id) {
case WM8753_PCMDIV:
- reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0x003f;
- wm8753_write(codec, WM8753_CLOCK, reg | div);
+ reg = snd_soc_read(codec, WM8753_CLOCK) & 0x003f;
+ snd_soc_write(codec, WM8753_CLOCK, reg | div);
break;
case WM8753_BCLKDIV:
- reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x01c7;
- wm8753_write(codec, WM8753_SRATE2, reg | div);
+ reg = snd_soc_read(codec, WM8753_SRATE2) & 0x01c7;
+ snd_soc_write(codec, WM8753_SRATE2, reg | div);
break;
case WM8753_VXCLKDIV:
- reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x003f;
- wm8753_write(codec, WM8753_SRATE2, reg | div);
+ reg = snd_soc_read(codec, WM8753_SRATE2) & 0x003f;
+ snd_soc_write(codec, WM8753_SRATE2, reg | div);
break;
default:
return -EINVAL;
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
- u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01e0;
+ u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01e0;
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
return -EINVAL;
}
- wm8753_write(codec, WM8753_HIFI, hifi);
+ snd_soc_write(codec, WM8753_HIFI, hifi);
return 0;
}
struct snd_soc_codec *codec = codec_dai->codec;
u16 ioctl, hifi;
- hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x011f;
- ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x00ae;
+ hifi = snd_soc_read(codec, WM8753_HIFI) & 0x011f;
+ ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x00ae;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
return -EINVAL;
}
- wm8753_write(codec, WM8753_HIFI, hifi);
- wm8753_write(codec, WM8753_IOCTL, ioctl);
+ snd_soc_write(codec, WM8753_HIFI, hifi);
+ snd_soc_write(codec, WM8753_IOCTL, ioctl);
return 0;
}
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
- u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
- u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
+ u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x01c0;
+ u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01f3;
int coeff;
/* is digital filter coefficient valid ? */
printk(KERN_ERR "wm8753 invalid MCLK or rate\n");
return coeff;
}
- wm8753_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) |
+ snd_soc_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) |
coeff_div[coeff].usb);
/* bit size */
break;
}
- wm8753_write(codec, WM8753_HIFI, hifi);
+ snd_soc_write(codec, WM8753_HIFI, hifi);
return 0;
}
u16 clock;
/* set clk source as pcmclk */
- clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;
- wm8753_write(codec, WM8753_CLOCK, clock);
+ clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
+ snd_soc_write(codec, WM8753_CLOCK, clock);
if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)
return -EINVAL;
u16 clock;
/* set clk source as pcmclk */
- clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;
- wm8753_write(codec, WM8753_CLOCK, clock);
+ clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
+ snd_soc_write(codec, WM8753_CLOCK, clock);
if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)
return -EINVAL;
u16 clock;
/* set clk source as mclk */
- clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;
- wm8753_write(codec, WM8753_CLOCK, clock | 0x4);
+ clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
+ snd_soc_write(codec, WM8753_CLOCK, clock | 0x4);
if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0)
return -EINVAL;
static int wm8753_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;
+ u16 mute_reg = snd_soc_read(codec, WM8753_DAC) & 0xfff7;
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
/* the digital mute covers the HiFi and Voice DAC's on the WM8753.
* make sure we check if they are not both active when we mute */
if (mute && wm8753->dai_func == 1) {
if (!codec->active)
- wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
+ snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);
} else {
if (mute)
- wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
+ snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);
else
- wm8753_write(codec, WM8753_DAC, mute_reg);
+ snd_soc_write(codec, WM8753_DAC, mute_reg);
}
return 0;
static int wm8753_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e;
+ u16 pwr_reg = snd_soc_read(codec, WM8753_PWR1) & 0xfe3e;
switch (level) {
case SND_SOC_BIAS_ON:
/* set vmid to 50k and unmute dac */
- wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
+ snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
break;
case SND_SOC_BIAS_PREPARE:
/* set vmid to 5k for quick power up */
- wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
+ snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
break;
case SND_SOC_BIAS_STANDBY:
/* mute dac and set vmid to 500k, enable VREF */
- wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141);
+ snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x0141);
break;
case SND_SOC_BIAS_OFF:
- wm8753_write(codec, WM8753_PWR1, 0x0001);
+ snd_soc_write(codec, WM8753_PWR1, 0x0001);
break;
}
codec->bias_level = level;
else
dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) + 1];
}
- wm8753_write(codec, WM8753_IOCTL, wm8753->dai_func);
+ snd_soc_write(codec, WM8753_IOCTL, wm8753->dai_func);
}
static void wm8753_work(struct work_struct *work)
static int wm8753_resume(struct snd_soc_codec *codec)
{
+ u16 *reg_cache = codec->reg_cache;
int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) {
- if (i + 1 == WM8753_RESET)
+ for (i = 1; i < ARRAY_SIZE(wm8753_reg); i++) {
+ if (i == WM8753_RESET)
continue;
/* No point in writing hardware default values back */
- if (cache[i] == wm8753_reg[i])
+ if (reg_cache[i] == wm8753_reg[i])
continue;
- data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
+ snd_soc_write(codec, i, reg_cache[i]);
}
wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
static int wm8753_probe(struct snd_soc_codec *codec)
{
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
- int ret = 0, reg;
+ int ret;
INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
msecs_to_jiffies(caps_charge));
/* set the update bits */
- reg = wm8753_read_reg_cache(codec, WM8753_LDAC);
- wm8753_write(codec, WM8753_LDAC, reg | 0x0100);
- reg = wm8753_read_reg_cache(codec, WM8753_RDAC);
- wm8753_write(codec, WM8753_RDAC, reg | 0x0100);
- reg = wm8753_read_reg_cache(codec, WM8753_LADC);
- wm8753_write(codec, WM8753_LADC, reg | 0x0100);
- reg = wm8753_read_reg_cache(codec, WM8753_RADC);
- wm8753_write(codec, WM8753_RADC, reg | 0x0100);
- reg = wm8753_read_reg_cache(codec, WM8753_LOUT1V);
- wm8753_write(codec, WM8753_LOUT1V, reg | 0x0100);
- reg = wm8753_read_reg_cache(codec, WM8753_ROUT1V);
- wm8753_write(codec, WM8753_ROUT1V, reg | 0x0100);
- reg = wm8753_read_reg_cache(codec, WM8753_LOUT2V);
- wm8753_write(codec, WM8753_LOUT2V, reg | 0x0100);
- reg = wm8753_read_reg_cache(codec, WM8753_ROUT2V);
- wm8753_write(codec, WM8753_ROUT2V, reg | 0x0100);
- reg = wm8753_read_reg_cache(codec, WM8753_LINVOL);
- wm8753_write(codec, WM8753_LINVOL, reg | 0x0100);
- reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);
- wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);
+ snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_LOUT1V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_ROUT1V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_LOUT2V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_ROUT2V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_LINVOL, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_RINVOL, 0x0100, 0x0100);
snd_soc_add_controls(codec, wm8753_snd_controls,
ARRAY_SIZE(wm8753_snd_controls));
/* codec private data */
struct wm8904_priv {
- u16 reg_cache[WM8904_MAX_REGISTER + 1];
-
enum wm8904_type devtype;
void *control_data;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
- return wm8904->deemph;
+ ucontrol->value.enumerated.item[0] = wm8904->deemph;
+ return 0;
}
static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
static void wm8904_sync_cache(struct snd_soc_codec *codec)
{
- struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
int i;
if (!codec->cache_sync)
/* Sync back cached values if they're different from the
* hardware default.
*/
- for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) {
+ for (i = 1; i < codec->driver->reg_cache_size; i++) {
if (!wm8904_access[i].writable)
continue;
- if (wm8904->reg_cache[i] == wm8904_reg[i])
+ if (reg_cache[i] == wm8904_reg[i])
continue;
- snd_soc_write(codec, i, wm8904->reg_cache[i]);
+ snd_soc_write(codec, i, reg_cache[i]);
}
codec->cache_sync = 0;
{
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
+ u16 *reg_cache = codec->reg_cache;
int ret, i;
codec->cache_sync = 1;
}
/* Change some default settings - latch VU and enable ZC */
- wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
- wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
- wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU;
- wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU;
- wm8904->reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU |
+ reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
+ reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
+ reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU;
+ reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU;
+ reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU |
WM8904_HPOUTLZC;
- wm8904->reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU |
+ reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU |
WM8904_HPOUTRZC;
- wm8904->reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU |
+ reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU |
WM8904_LINEOUTLZC;
- wm8904->reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU |
+ reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU |
WM8904_LINEOUTRZC;
- wm8904->reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE;
+ reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE;
/* Apply configuration from the platform data. */
if (wm8904->pdata) {
if (!pdata->gpio_cfg[i])
continue;
- wm8904->reg_cache[WM8904_GPIO_CONTROL_1 + i]
+ reg_cache[WM8904_GPIO_CONTROL_1 + i]
= pdata->gpio_cfg[i] & 0xffff;
}
/* Zero is the default value for these anyway */
for (i = 0; i < WM8904_MIC_REGS; i++)
- wm8904->reg_cache[WM8904_MIC_BIAS_CONTROL_0 + i]
+ reg_cache[WM8904_MIC_BIAS_CONTROL_0 + i]
= pdata->mic_cfg[i];
}
/* Set Class W by default - this will be managed by the Class
* G widget at runtime where bypass paths are available.
*/
- wm8904->reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR;
+ reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR;
/* Use normal bias source */
- wm8904->reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL;
+ reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL;
wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
i2c_set_clientdata(i2c, wm8940);
wm8940->control_data = i2c;
+ wm8940->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8940, &wm8940_dai, 1);
struct wm8955_priv {
enum snd_soc_control_type control_type;
- u16 reg_cache[WM8955_MAX_REGISTER + 1];
-
unsigned int mclk_rate;
int deemph;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
- return wm8955->deemph;
+ ucontrol->value.enumerated.item[0] = wm8955->deemph;
+ return 0;
}
static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
enum snd_soc_bias_level level)
{
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
int ret, i;
switch (level) {
/* Sync back cached values if they're
* different from the hardware default.
*/
- for (i = 0; i < ARRAY_SIZE(wm8955->reg_cache); i++) {
+ for (i = 0; i < codec->driver->reg_cache_size; i++) {
if (i == WM8955_RESET)
continue;
- if (wm8955->reg_cache[i] == wm8955_reg[i])
+ if (reg_cache[i] == wm8955_reg[i])
continue;
- snd_soc_write(codec, i, wm8955->reg_cache[i]);
+ snd_soc_write(codec, i, reg_cache[i]);
}
/* Enable VREF and VMID */
{
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);
+ u16 *reg_cache = codec->reg_cache;
int ret, i;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8955->control_type);
}
/* Change some default settings - latch VU and enable ZC */
- wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
- wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
- wm8955->reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC;
- wm8955->reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC;
- wm8955->reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC;
- wm8955->reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC;
- wm8955->reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC;
+ reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
+ reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
+ reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC;
+ reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC;
+ reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC;
+ reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC;
+ reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC;
/* Also enable adaptive bass boost by default */
- wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
+ reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
/* Set platform data values */
if (pdata) {
if (pdata->out2_speaker)
- wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2]
+ reg_cache[WM8955_ADDITIONAL_CONTROL_2]
|= WM8955_ROUT2INV;
if (pdata->monoin_diff)
- wm8955->reg_cache[WM8955_MONO_OUT_MIX_1]
+ reg_cache[WM8955_MONO_OUT_MIX_1]
|= WM8955_DMEN;
}
return -ENOMEM;
i2c_set_clientdata(i2c, wm8955);
+ wm8955->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8955, &wm8955_dai, 1);
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
- return wm8960->deemph;
+ ucontrol->value.enumerated.item[0] = wm8960->deemph;
+ return 0;
}
static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
return -ENOMEM;
i2c_set_clientdata(i2c, wm8960);
+ wm8960->control_type = SND_SOC_I2C;
wm8960->control_data = i2c;
ret = snd_soc_register_codec(&i2c->dev,
struct wm8962_priv {
struct snd_soc_codec *codec;
- u16 reg_cache[WM8962_MAX_REGISTER + 1];
-
int sysclk;
int sysclk_rate;
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
- u16 *reg_cache = wm8962->reg_cache;
+ u16 *reg_cache = codec->reg_cache;
int ret;
/* Apply the update (if any) */
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
- u16 *reg_cache = wm8962->reg_cache;
+ u16 *reg_cache = codec->reg_cache;
int ret;
/* Apply the update (if any) */
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
- u16 *reg_cache = wm8962->reg_cache;
+ u16 *reg_cache = codec->reg_cache;
int reg;
switch (w->shift) {
static void wm8962_sync_cache(struct snd_soc_codec *codec)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
int i;
if (!codec->cache_sync)
/* Sync back cached values if they're different from the
* hardware default.
*/
- for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
+ for (i = 1; i < codec->driver->reg_cache_size; i++) {
if (i == WM8962_SOFTWARE_RESET)
continue;
- if (wm8962->reg_cache[i] == wm8962_reg[i])
+ if (reg_cache[i] == wm8962_reg[i])
continue;
- snd_soc_write(codec, i, wm8962->reg_cache[i]);
+ snd_soc_write(codec, i, reg_cache[i]);
}
codec->cache_sync = 0;
#ifdef CONFIG_PM
static int wm8962_resume(struct snd_soc_codec *codec)
{
- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
u16 *reg_cache = codec->reg_cache;
int i;
/* Restore the registers */
- for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
+ for (i = 1; i < codec->driver->reg_cache_size; i++) {
switch (i) {
case WM8962_SOFTWARE_RESET:
continue;
struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
dev);
+ u16 *reg_cache = codec->reg_cache;
int i, trigger, irq_pol;
wm8962->codec = codec;
/* Put the speakers into mono mode? */
if (pdata->spk_mono)
- wm8962->reg_cache[WM8962_CLASS_D_CONTROL_2]
+ reg_cache[WM8962_CLASS_D_CONTROL_2]
|= WM8962_SPK_MONO;
/* Micbias setup, detection enable and detection
}
/* Latch volume update bits */
- wm8962->reg_cache[WM8962_LEFT_INPUT_VOLUME] |= WM8962_IN_VU;
- wm8962->reg_cache[WM8962_RIGHT_INPUT_VOLUME] |= WM8962_IN_VU;
- wm8962->reg_cache[WM8962_LEFT_ADC_VOLUME] |= WM8962_ADC_VU;
- wm8962->reg_cache[WM8962_RIGHT_ADC_VOLUME] |= WM8962_ADC_VU;
- wm8962->reg_cache[WM8962_LEFT_DAC_VOLUME] |= WM8962_DAC_VU;
- wm8962->reg_cache[WM8962_RIGHT_DAC_VOLUME] |= WM8962_DAC_VU;
- wm8962->reg_cache[WM8962_SPKOUTL_VOLUME] |= WM8962_SPKOUT_VU;
- wm8962->reg_cache[WM8962_SPKOUTR_VOLUME] |= WM8962_SPKOUT_VU;
- wm8962->reg_cache[WM8962_HPOUTL_VOLUME] |= WM8962_HPOUT_VU;
- wm8962->reg_cache[WM8962_HPOUTR_VOLUME] |= WM8962_HPOUT_VU;
+ reg_cache[WM8962_LEFT_INPUT_VOLUME] |= WM8962_IN_VU;
+ reg_cache[WM8962_RIGHT_INPUT_VOLUME] |= WM8962_IN_VU;
+ reg_cache[WM8962_LEFT_ADC_VOLUME] |= WM8962_ADC_VU;
+ reg_cache[WM8962_RIGHT_ADC_VOLUME] |= WM8962_ADC_VU;
+ reg_cache[WM8962_LEFT_DAC_VOLUME] |= WM8962_DAC_VU;
+ reg_cache[WM8962_RIGHT_DAC_VOLUME] |= WM8962_DAC_VU;
+ reg_cache[WM8962_SPKOUTL_VOLUME] |= WM8962_SPKOUT_VU;
+ reg_cache[WM8962_SPKOUTR_VOLUME] |= WM8962_SPKOUT_VU;
+ reg_cache[WM8962_HPOUTL_VOLUME] |= WM8962_HPOUT_VU;
+ reg_cache[WM8962_HPOUTR_VOLUME] |= WM8962_HPOUT_VU;
wm8962_add_widgets(codec);
if (wm8971 == NULL)
return -ENOMEM;
+ wm8971->control_type = SND_SOC_I2C;
i2c_set_clientdata(i2c, wm8971);
ret = snd_soc_register_codec(&i2c->dev,
return -ENOMEM;
i2c_set_clientdata(i2c, wm9081);
+ wm9081->control_type = SND_SOC_I2C;
wm9081->control_data = i2c;
ret = snd_soc_register_codec(&i2c->dev,
/* This struct is used to save the context */
struct wm9090_priv {
struct mutex mutex;
- u16 reg_cache[WM9090_MAX_REGISTER + 1];
struct wm9090_platform_data pdata;
void *control_data;
};
static int wm9090_probe(struct snd_soc_codec *codec)
{
struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
int ret;
codec->control_data = wm9090->control_data;
/* Configure some defaults; they will be written out when we
* bring the bias up.
*/
- wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
+ reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
| WM9090_IN1A_ZC;
- wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
+ reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
| WM9090_IN1B_ZC;
- wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
+ reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
| WM9090_IN2A_ZC;
- wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
+ reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
| WM9090_IN2B_ZC;
- wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
+ reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
- wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
+ reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
- wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
+ reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
- wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
+ reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
case SND_SOC_DAPM_STREAM_RESUME:
sys_power = 1;
break;
+ case SND_SOC_DAPM_STREAM_STOP:
+ sys_power = !!codec->active;
+ break;
case SND_SOC_DAPM_STREAM_SUSPEND:
sys_power = 0;
break;
static int __cmd_buildid_list(void)
{
- int err = -1;
struct perf_session *session;
session = perf_session__new(input_name, O_RDONLY, force, false);
perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
perf_session__delete(session);
- return err;
+ return 0;
}
int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
!params.show_lines))
usage_with_options(probe_usage, options);
+ /*
+ * Only consider the user's kernel image path if given.
+ */
+ symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
+
if (params.list_events) {
if (params.mod_events) {
pr_err(" Error: Don't use --list with --add/--del.\n");
const char *name, bool is_kallsyms)
{
const size_t size = PATH_MAX;
- char *filename = malloc(size),
+ char *realname = realpath(name, NULL),
+ *filename = malloc(size),
*linkname = malloc(size), *targetname;
int len, err = -1;
- if (filename == NULL || linkname == NULL)
+ if (realname == NULL || filename == NULL || linkname == NULL)
goto out_free;
len = snprintf(filename, size, "%s%s%s",
- debugdir, is_kallsyms ? "/" : "", name);
+ debugdir, is_kallsyms ? "/" : "", realname);
if (mkdir_p(filename, 0755))
goto out_free;
if (is_kallsyms) {
if (copyfile("/proc/kallsyms", filename))
goto out_free;
- } else if (link(name, filename) && copyfile(name, filename))
+ } else if (link(realname, filename) && copyfile(name, filename))
goto out_free;
}
if (symlink(targetname, linkname) == 0)
err = 0;
out_free:
+ free(realname);
free(filename);
free(linkname);
return err;
static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
int depth, int depth_mask, int period,
- u64 total_samples, int hits,
+ u64 total_samples, u64 hits,
int left_margin)
{
int i;
const char *kernel_get_module_path(const char *module)
{
struct dso *dso;
+ struct map *map;
+ const char *vmlinux_name;
if (module) {
list_for_each_entry(dso, &machine.kernel_dsos, node) {
}
pr_debug("Failed to find module %s.\n", module);
return NULL;
+ }
+
+ map = machine.vmlinux_maps[MAP__FUNCTION];
+ dso = map->dso;
+
+ vmlinux_name = symbol_conf.vmlinux_name;
+ if (vmlinux_name) {
+ if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0)
+ return NULL;
} else {
- dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;
- if (dso__load_vmlinux_path(dso,
- machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
+ if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
pr_debug("Failed to load kernel map.\n");
return NULL;
}
}
/* Dwarf FL wrappers */
-
-static int __linux_kernel_find_elf(Dwfl_Module *mod,
- void **userdata,
- const char *module_name,
- Dwarf_Addr base,
- char **file_name, Elf **elfp)
-{
- int fd;
- const char *path = kernel_get_module_path(module_name);
-
- if (path) {
- fd = open(path, O_RDONLY);
- if (fd >= 0) {
- *file_name = strdup(path);
- return fd;
- }
- }
- /* If failed, try to call standard method */
- return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
- file_name, elfp);
-}
-
static char *debuginfo_path; /* Currently dummy */
static const Dwfl_Callbacks offline_callbacks = {
.find_elf = dwfl_build_id_find_elf,
};
-static const Dwfl_Callbacks kernel_callbacks = {
- .find_debuginfo = dwfl_standard_find_debuginfo,
- .debuginfo_path = &debuginfo_path,
-
- .find_elf = __linux_kernel_find_elf,
- .section_address = dwfl_linux_kernel_module_section_address,
-};
-
/* Get a Dwarf from offline image */
static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
{
return dbg;
}
+#if _ELFUTILS_PREREQ(0, 148)
+/* This method is buggy if elfutils is older than 0.148 */
+static int __linux_kernel_find_elf(Dwfl_Module *mod,
+ void **userdata,
+ const char *module_name,
+ Dwarf_Addr base,
+ char **file_name, Elf **elfp)
+{
+ int fd;
+ const char *path = kernel_get_module_path(module_name);
+
+ pr_debug2("Use file %s for %s\n", path, module_name);
+ if (path) {
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ *file_name = strdup(path);
+ return fd;
+ }
+ }
+ /* If failed, try to call standard method */
+ return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
+ file_name, elfp);
+}
+
+static const Dwfl_Callbacks kernel_callbacks = {
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .debuginfo_path = &debuginfo_path,
+
+ .find_elf = __linux_kernel_find_elf,
+ .section_address = dwfl_linux_kernel_module_section_address,
+};
+
/* Get a Dwarf from live kernel image */
static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
Dwarf_Addr *bias)
dbg = dwfl_addrdwarf(*dwflp, addr, bias);
/* Here, check whether we could get a real dwarf */
if (!dbg) {
+ pr_debug("Failed to find kernel dwarf at %lx\n",
+ (unsigned long)addr);
dwfl_end(*dwflp);
*dwflp = NULL;
}
return dbg;
}
+#else
+/* With older elfutils, this just support kernel module... */
+static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp,
+ Dwarf_Addr *bias)
+{
+ int fd;
+ const char *path = kernel_get_module_path("kernel");
+
+ if (!path) {
+ pr_err("Failed to find vmlinux path\n");
+ return NULL;
+ }
+
+ pr_debug2("Use file %s for debuginfo\n", path);
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ return dwfl_init_offline_dwarf(fd, dwflp, bias);
+}
+#endif
/* Dwarf wrappers */
if (!*pat) /* Tail wild card matches all */
return true;
while (*str)
- if (strglobmatch(str++, pat))
+ if (__match_glob(str++, pat, ignore_space))
return true;
}
return !*str && !*pat;
return -1;
}
-static int dso__load_vmlinux(struct dso *self, struct map *map,
- const char *vmlinux, symbol_filter_t filter)
+int dso__load_vmlinux(struct dso *self, struct map *map,
+ const char *vmlinux, symbol_filter_t filter)
{
int err = -1, fd;
struct dso *__dsos__findnew(struct list_head *head, const char *name);
int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
+int dso__load_vmlinux(struct dso *self, struct map *map,
+ const char *vmlinux, symbol_filter_t filter);
int dso__load_vmlinux_path(struct dso *self, struct map *map,
symbol_filter_t filter);
int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,