From 1868f4aa5a4a72bbe0b7db6c1d4ee666824c3895 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 4 May 2005 15:29:35 -0500 Subject: JFS: fix sparse warnings by moving extern declarations to headers Signed-off-by: Dave Kleikamp diff --git a/fs/jfs/file.c b/fs/jfs/file.c index a87b06f..c2c19c9 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -1,6 +1,6 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 - * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * Copyright (C) International Business Machines Corp., 2000-2002 + * Portions Copyright (C) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,16 +19,13 @@ #include #include "jfs_incore.h" +#include "jfs_inode.h" #include "jfs_dmap.h" #include "jfs_txnmgr.h" #include "jfs_xattr.h" #include "jfs_acl.h" #include "jfs_debug.h" - -extern int jfs_commit_inode(struct inode *, int); -extern void jfs_truncate(struct inode *); - int jfs_fsync(struct file *file, struct dentry *dentry, int datasync) { struct inode *inode = dentry->d_inode; diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 24a6891..2137138 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -23,6 +23,7 @@ #include #include #include "jfs_incore.h" +#include "jfs_inode.h" #include "jfs_filsys.h" #include "jfs_imap.h" #include "jfs_extent.h" @@ -30,14 +31,6 @@ #include "jfs_debug.h" -extern struct inode_operations jfs_dir_inode_operations; -extern struct inode_operations jfs_file_inode_operations; -extern struct inode_operations jfs_symlink_inode_operations; -extern struct file_operations jfs_dir_operations; -extern struct file_operations jfs_file_operations; -struct address_space_operations jfs_aops; -extern int freeZeroLink(struct inode *); - void jfs_read_inode(struct inode *inode) { if (diRead(inode)) { @@ -136,7 +129,7 @@ void jfs_delete_inode(struct inode *inode) jfs_info("In jfs_delete_inode, inode = 0x%p", inode); if (test_cflag(COMMIT_Freewmap, inode)) - freeZeroLink(inode); + jfs_free_zero_link(inode); diFree(inode); diff --git a/fs/jfs/jfs_debug.c b/fs/jfs/jfs_debug.c index 91a0a88..4caea6b 100644 --- a/fs/jfs/jfs_debug.c +++ b/fs/jfs/jfs_debug.c @@ -58,8 +58,6 @@ void dump_mem(char *label, void *data, int length) static struct proc_dir_entry *base; #ifdef CONFIG_JFS_DEBUG -extern read_proc_t jfs_txanchor_read; - static int loglevel_read(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -97,14 +95,6 @@ static int loglevel_write(struct file *file, const char __user *buffer, } #endif - -#ifdef CONFIG_JFS_STATISTICS -extern read_proc_t jfs_lmstats_read; -extern read_proc_t jfs_txstats_read; -extern read_proc_t jfs_xtstat_read; -extern read_proc_t jfs_mpstat_read; -#endif - static struct { const char *name; read_proc_t *read_fn; diff --git a/fs/jfs/jfs_debug.h b/fs/jfs/jfs_debug.h index a38079a..ddffbbd 100644 --- a/fs/jfs/jfs_debug.h +++ b/fs/jfs/jfs_debug.h @@ -1,6 +1,6 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 - * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * Copyright (C) International Business Machines Corp., 2000-2002 + * Portions Copyright (C) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +31,9 @@ * CONFIG_JFS_DEBUG or CONFIG_JFS_STATISTICS is defined */ #if defined(CONFIG_PROC_FS) && (defined(CONFIG_JFS_DEBUG) || defined(CONFIG_JFS_STATISTICS)) - #define PROC_FS_JFS +#define PROC_FS_JFS +extern void jfs_proc_init(void); +extern void jfs_proc_clean(void); #endif /* @@ -65,8 +67,8 @@ extern int jfsloglevel; -/* dump memory contents */ extern void dump_mem(char *label, void *data, int length); +extern int jfs_txanchor_read(char *, char **, off_t, int, int *, void *); /* information message: e.g., configuration, major event */ #define jfs_info(fmt, arg...) do { \ @@ -110,6 +112,11 @@ extern void dump_mem(char *label, void *data, int length); * ---------- */ #ifdef CONFIG_JFS_STATISTICS +extern int jfs_lmstats_read(char *, char **, off_t, int, int *, void *); +extern int jfs_txstats_read(char *, char **, off_t, int, int *, void *); +extern int jfs_mpstat_read(char *, char **, off_t, int, int *, void *); +extern int jfs_xtstat_read(char *, char **, off_t, int, int *, void *); + #define INCREMENT(x) ((x)++) #define DECREMENT(x) ((x)--) #define HIGHWATERMARK(x,y) ((x) = max((x), (y))) diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index 1953acb..4879603 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c @@ -19,6 +19,7 @@ #include #include #include "jfs_incore.h" +#include "jfs_inode.h" #include "jfs_superblock.h" #include "jfs_dmap.h" #include "jfs_extent.h" @@ -33,12 +34,6 @@ static int extBrealloc(struct inode *, s64, s64, s64 *, s64 *); #endif static s64 extRoundDown(s64 nb); -/* - * external references - */ -extern int jfs_commit_inode(struct inode *, int); - - #define DPD(a) (printk("(a): %d\n",(a))) #define DPC(a) (printk("(a): %c\n",(a))) #define DPL1(a) \ diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 7acff2c..971af29 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -47,6 +47,7 @@ #include #include "jfs_incore.h" +#include "jfs_inode.h" #include "jfs_filsys.h" #include "jfs_dinode.h" #include "jfs_dmap.h" @@ -69,11 +70,6 @@ #define AG_UNLOCK(imap,agno) up(&imap->im_aglock[agno]) /* - * external references - */ -extern struct address_space_operations jfs_aops; - -/* * forward references */ static int diAllocAG(struct inomap *, int, boolean_t, struct inode *); diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c index 84f2459..2af5efb 100644 --- a/fs/jfs/jfs_inode.c +++ b/fs/jfs/jfs_inode.c @@ -19,6 +19,7 @@ #include #include #include "jfs_incore.h" +#include "jfs_inode.h" #include "jfs_filsys.h" #include "jfs_imap.h" #include "jfs_dinode.h" diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index 3df91fb..b54bac5 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2001 + * Copyright (C) International Business Machines Corp., 2000-2001 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,5 +19,22 @@ #define _H_JFS_INODE extern struct inode *ialloc(struct inode *, umode_t); +extern int jfs_fsync(struct file *, struct dentry *, int); +extern void jfs_read_inode(struct inode *); +extern int jfs_commit_inode(struct inode *, int); +extern int jfs_write_inode(struct inode*, int); +extern void jfs_delete_inode(struct inode *); +extern void jfs_dirty_inode(struct inode *); +extern void jfs_truncate(struct inode *); +extern void jfs_truncate_nolock(struct inode *, loff_t); +extern void jfs_free_zero_link(struct inode *); +extern struct dentry *jfs_get_parent(struct dentry *dentry); +extern struct address_space_operations jfs_aops; +extern struct inode_operations jfs_dir_inode_operations; +extern struct file_operations jfs_dir_operations; +extern struct inode_operations jfs_file_inode_operations; +extern struct file_operations jfs_file_operations; +extern struct inode_operations jfs_symlink_inode_operations; +extern struct dentry_operations jfs_ci_dentry_operations; #endif /* _H_JFS_INODE */ diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index dfa1200..c5cc03b 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -71,6 +71,7 @@ #include "jfs_incore.h" #include "jfs_filsys.h" #include "jfs_metapage.h" +#include "jfs_superblock.h" #include "jfs_txnmgr.h" #include "jfs_debug.h" @@ -167,14 +168,6 @@ static struct jfs_log *dummy_log = NULL; static DECLARE_MUTEX(jfs_log_sem); /* - * external references - */ -extern void txLazyUnlock(struct tblock * tblk); -extern int jfs_stop_threads; -extern struct completion jfsIOwait; -extern int jfs_tlocks_low; - -/* * forward references */ static int lmWriteRecord(struct jfs_log * log, struct tblock * tblk, diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h index 51291fb..747114c 100644 --- a/fs/jfs/jfs_logmgr.h +++ b/fs/jfs/jfs_logmgr.h @@ -507,6 +507,8 @@ extern int lmLogClose(struct super_block *sb); extern int lmLogShutdown(struct jfs_log * log); extern int lmLogInit(struct jfs_log * log); extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize); +extern int lmGroupCommit(struct jfs_log *, struct tblock *); +extern int jfsIOWait(void *); extern void jfs_flush_journal(struct jfs_log * log, int wait); extern void jfs_syncpt(struct jfs_log *log); diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 41bf078..aa1cc7b 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -726,12 +726,12 @@ void force_metapage(struct metapage *mp) page_cache_release(page); } -extern void hold_metapage(struct metapage *mp) +void hold_metapage(struct metapage *mp) { lock_page(mp->page); } -extern void put_metapage(struct metapage *mp) +void put_metapage(struct metapage *mp) { if (mp->count || mp->nohomeok) { /* Someone else will release this */ diff --git a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h index 991e9fb..f0b7d32 100644 --- a/fs/jfs/jfs_metapage.h +++ b/fs/jfs/jfs_metapage.h @@ -1,6 +1,6 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 - * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * Copyright (C) International Business Machines Corp., 2000-2002 + * Portions Copyright (C) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,6 +58,8 @@ struct metapage { #define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag) /* function prototypes */ +extern int metapage_init(void); +extern void metapage_exit(void); extern struct metapage *__get_metapage(struct inode *inode, unsigned long lblock, unsigned int size, int absolute, unsigned long new); diff --git a/fs/jfs/jfs_superblock.h b/fs/jfs/jfs_superblock.h index ab0566f..fcf781b 100644 --- a/fs/jfs/jfs_superblock.h +++ b/fs/jfs/jfs_superblock.h @@ -109,5 +109,16 @@ struct jfs_superblock { extern int readSuper(struct super_block *, struct buffer_head **); extern int updateSuper(struct super_block *, uint); extern void jfs_error(struct super_block *, const char *, ...); +extern int jfs_mount(struct super_block *); +extern int jfs_mount_rw(struct super_block *, int); +extern int jfs_umount(struct super_block *); +extern int jfs_umount_rw(struct super_block *); + +extern int jfs_stop_threads; +extern struct completion jfsIOwait; +extern wait_queue_head_t jfs_IO_thread_wait; +extern wait_queue_head_t jfs_commit_thread_wait; +extern wait_queue_head_t jfs_sync_thread_wait; +extern int jfs_extendfs(struct super_block *, s64, int); #endif /*_H_JFS_SUPERBLOCK */ diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index e93d01a..8cbaaff 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -42,7 +42,6 @@ * hold on to mp+lock thru update of maps */ - #include #include #include @@ -51,6 +50,7 @@ #include #include #include "jfs_incore.h" +#include "jfs_inode.h" #include "jfs_filsys.h" #include "jfs_metapage.h" #include "jfs_dinode.h" @@ -109,7 +109,6 @@ static int TxLockHWM; /* High water mark for number of txLocks used */ static int TxLockVHWM; /* Very High water mark */ struct tlock *TxLock; /* transaction lock table */ - /* * transaction management lock */ @@ -149,7 +148,6 @@ static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event) #define TXN_WAKEUP(event) wake_up_all(event) - /* * statistics */ @@ -161,16 +159,6 @@ static struct { int waitlock; /* 4: # of tlock wait */ } stattx; - -/* - * external references - */ -extern int lmGroupCommit(struct jfs_log *, struct tblock *); -extern int jfs_commit_inode(struct inode *, int); -extern int jfs_stop_threads; - -extern struct completion jfsIOwait; - /* * forward references */ @@ -358,7 +346,6 @@ void txExit(void) TxBlock = NULL; } - /* * NAME: txBegin() * @@ -460,7 +447,6 @@ tid_t txBegin(struct super_block *sb, int flag) return t; } - /* * NAME: txBeginAnon() * @@ -503,7 +489,6 @@ void txBeginAnon(struct super_block *sb) TXN_UNLOCK(); } - /* * txEnd() * @@ -592,7 +577,6 @@ wakeup: TXN_WAKEUP(&TxAnchor.freewait); } - /* * txLock() * @@ -868,7 +852,6 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp, return NULL; } - /* * NAME: txRelease() * @@ -908,7 +891,6 @@ static void txRelease(struct tblock * tblk) TXN_UNLOCK(); } - /* * NAME: txUnlock() * @@ -996,7 +978,6 @@ static void txUnlock(struct tblock * tblk) } } - /* * txMaplock() * @@ -1069,7 +1050,6 @@ struct tlock *txMaplock(tid_t tid, struct inode *ip, int type) return tlck; } - /* * txLinelock() * @@ -1103,8 +1083,6 @@ struct linelock *txLinelock(struct linelock * tlock) return linelock; } - - /* * transaction commit management * ----------------------------- @@ -1373,7 +1351,6 @@ int txCommit(tid_t tid, /* transaction identifier */ return rc; } - /* * NAME: txLog() * @@ -1437,7 +1414,6 @@ static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd) return rc; } - /* * diLog() * @@ -1465,7 +1441,6 @@ static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, if (tlck->type & tlckENTRY) { /* log after-image for logredo(): */ lrd->type = cpu_to_le16(LOG_REDOPAGE); -// *pxd = mp->cm_pxd; PXDaddress(pxd, mp->index); PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits); @@ -1552,7 +1527,6 @@ static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, return rc; } - /* * dataLog() * @@ -1599,7 +1573,6 @@ static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, return 0; } - /* * dtLog() * @@ -1639,7 +1612,6 @@ static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, lrd->log.redopage.type |= cpu_to_le16(LOG_EXTEND); else lrd->log.redopage.type |= cpu_to_le16(LOG_NEW); -// *pxd = mp->cm_pxd; PXDaddress(pxd, mp->index); PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits); @@ -1704,7 +1676,6 @@ static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, return; } - /* * xtLog() * @@ -1760,7 +1731,6 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, * applying the after-image to the meta-data page. */ lrd->type = cpu_to_le16(LOG_REDOPAGE); -// *page_pxd = mp->cm_pxd; PXDaddress(page_pxd, mp->index); PXDlength(page_pxd, mp->logical_size >> tblk->sb->s_blocksize_bits); @@ -2093,7 +2063,6 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, return; } - /* * mapLog() * @@ -2180,7 +2149,6 @@ void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, } } - /* * txEA() * @@ -2233,7 +2201,6 @@ void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea) } } - /* * txForce() * @@ -2300,7 +2267,6 @@ void txForce(struct tblock * tblk) } } - /* * txUpdateMap() * @@ -2437,7 +2403,6 @@ static void txUpdateMap(struct tblock * tblk) } } - /* * txAllocPMap() * @@ -2509,7 +2474,6 @@ static void txAllocPMap(struct inode *ip, struct maplock * maplock, } } - /* * txFreeMap() * @@ -2611,7 +2575,6 @@ void txFreeMap(struct inode *ip, } } - /* * txFreelock() * @@ -2652,7 +2615,6 @@ void txFreelock(struct inode *ip) TXN_UNLOCK(); } - /* * txAbort() * diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h index b71b82c..59ad0f6 100644 --- a/fs/jfs/jfs_txnmgr.h +++ b/fs/jfs/jfs_txnmgr.h @@ -285,34 +285,26 @@ struct commit { /* * external declarations */ -extern struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage *mp, - int flag); - -extern struct tlock *txMaplock(tid_t tid, struct inode *ip, int flag); - -extern int txCommit(tid_t tid, int nip, struct inode **iplist, int flag); - -extern tid_t txBegin(struct super_block *sb, int flag); - -extern void txBeginAnon(struct super_block *sb); - -extern void txEnd(tid_t tid); - -extern void txAbort(tid_t tid, int dirty); - -extern struct linelock *txLinelock(struct linelock * tlock); - -extern void txFreeMap(struct inode *ip, struct maplock * maplock, - struct tblock * tblk, int maptype); - -extern void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea); - -extern void txFreelock(struct inode *ip); - -extern int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck); - -extern void txQuiesce(struct super_block *sb); - -extern void txResume(struct super_block *sb); +extern int jfs_tlocks_low; + +extern int txInit(void); +extern void txExit(void); +extern struct tlock *txLock(tid_t, struct inode *, struct metapage *, int); +extern struct tlock *txMaplock(tid_t, struct inode *, int); +extern int txCommit(tid_t, int, struct inode **, int); +extern tid_t txBegin(struct super_block *, int); +extern void txBeginAnon(struct super_block *); +extern void txEnd(tid_t); +extern void txAbort(tid_t, int); +extern struct linelock *txLinelock(struct linelock *); +extern void txFreeMap(struct inode *, struct maplock *, struct tblock *, int); +extern void txEA(tid_t, struct inode *, dxd_t *, dxd_t *); +extern void txFreelock(struct inode *); +extern int lmLog(struct jfs_log *, struct tblock *, struct lrd *, + struct tlock *); +extern void txQuiesce(struct super_block *); +extern void txResume(struct super_block *); +extern void txLazyUnlock(struct tblock *); +extern int jfs_lazycommit(void *); +extern int jfs_sync(void *); #endif /* _H_JFS_TXNMGR */ diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 8413a36..1cae14e 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -31,20 +31,9 @@ #include "jfs_acl.h" #include "jfs_debug.h" -extern struct inode_operations jfs_file_inode_operations; -extern struct inode_operations jfs_symlink_inode_operations; -extern struct file_operations jfs_file_operations; -extern struct address_space_operations jfs_aops; - -extern int jfs_fsync(struct file *, struct dentry *, int); -extern void jfs_truncate_nolock(struct inode *, loff_t); -extern int jfs_init_acl(struct inode *, struct inode *); - /* * forward references */ -struct inode_operations jfs_dir_inode_operations; -struct file_operations jfs_dir_operations; struct dentry_operations jfs_ci_dentry_operations; static s64 commitZeroLink(tid_t, struct inode *); @@ -655,7 +644,7 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip) /* - * NAME: freeZeroLink() + * NAME: jfs_free_zero_link() * * FUNCTION: for non-directory, called by iClose(), * free resources of a file from cache and WORKING map @@ -663,15 +652,12 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip) * while associated with a pager object, * * PARAMETER: ip - pointer to inode of file. - * - * RETURN: 0 -ok */ -int freeZeroLink(struct inode *ip) +void jfs_free_zero_link(struct inode *ip) { - int rc = 0; int type; - jfs_info("freeZeroLink: ip = 0x%p", ip); + jfs_info("jfs_free_zero_link: ip = 0x%p", ip); /* return if not reg or symbolic link or if size is * already ok. @@ -684,10 +670,10 @@ int freeZeroLink(struct inode *ip) case S_IFLNK: /* if its contained in inode nothing to do */ if (ip->i_size < IDATASIZE) - return 0; + return; break; default: - return 0; + return; } /* @@ -737,9 +723,7 @@ int freeZeroLink(struct inode *ip) * free xtree/data blocks from working block map; */ if (ip->i_size) - rc = xtTruncate(0, ip, 0, COMMIT_WMAP); - - return rc; + xtTruncate(0, ip, 0, COMMIT_WMAP); } /* diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 5e774ed..810a365 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -28,6 +28,7 @@ #include "jfs_incore.h" #include "jfs_filsys.h" +#include "jfs_inode.h" #include "jfs_metapage.h" #include "jfs_superblock.h" #include "jfs_dmap.h" @@ -62,37 +63,6 @@ module_param(jfsloglevel, int, 0644); MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)"); #endif -/* - * External declarations - */ -extern int jfs_mount(struct super_block *); -extern int jfs_mount_rw(struct super_block *, int); -extern int jfs_umount(struct super_block *); -extern int jfs_umount_rw(struct super_block *); - -extern int jfsIOWait(void *); -extern int jfs_lazycommit(void *); -extern int jfs_sync(void *); - -extern void jfs_read_inode(struct inode *inode); -extern void jfs_dirty_inode(struct inode *inode); -extern void jfs_delete_inode(struct inode *inode); -extern int jfs_write_inode(struct inode *inode, int wait); - -extern struct dentry *jfs_get_parent(struct dentry *dentry); -extern int jfs_extendfs(struct super_block *, s64, int); - -extern struct dentry_operations jfs_ci_dentry_operations; - -#ifdef PROC_FS_JFS /* see jfs_debug.h */ -extern void jfs_proc_init(void); -extern void jfs_proc_clean(void); -#endif - -extern wait_queue_head_t jfs_IO_thread_wait; -extern wait_queue_head_t jfs_commit_thread_wait; -extern wait_queue_head_t jfs_sync_thread_wait; - static void jfs_handle_error(struct super_block *sb) { struct jfs_sb_info *sbi = JFS_SBI(sb); @@ -593,11 +563,6 @@ static struct file_system_type jfs_fs_type = { .fs_flags = FS_REQUIRES_DEV, }; -extern int metapage_init(void); -extern int txInit(void); -extern void txExit(void); -extern void metapage_exit(void); - static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) { struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo; diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c index ef4c07e..287d8d6 100644 --- a/fs/jfs/symlink.c +++ b/fs/jfs/symlink.c @@ -1,5 +1,5 @@ /* - * Copyright (c) Christoph Hellwig, 2001-2002 + * Copyright (C) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include #include #include "jfs_incore.h" +#include "jfs_inode.h" #include "jfs_xattr.h" static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd) -- cgit v0.10.2 From dcc9871270aa3b1bbe2e61cc9c1d80e9b2e8099d Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 4 May 2005 15:30:51 -0500 Subject: JFS: cleanup - remove unneeded sanity check Signed-off-by: Dave Kleikamp diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 69007fd..cced2fe 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -272,7 +272,6 @@ int dbMount(struct inode *ipbmap) int dbUnmount(struct inode *ipbmap, int mounterror) { struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap; - int i; if (!(mounterror || isReadOnly(ipbmap))) dbSync(ipbmap); @@ -282,14 +281,6 @@ int dbUnmount(struct inode *ipbmap, int mounterror) */ truncate_inode_pages(ipbmap->i_mapping, 0); - /* - * Sanity Check - */ - for (i = 0; i < bmp->db_numag; i++) - if (atomic_read(&bmp->db_active[i])) - printk(KERN_ERR "dbUnmount: db_active[%d] = %d\n", - i, atomic_read(&bmp->db_active[i])); - /* free the memory for the in-memory bmap. */ kfree(bmp); -- cgit v0.10.2 From 7a694ca74958b97ae2d437c8a730bddd9e9792c3 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 4 May 2005 15:31:14 -0500 Subject: JFS: Fix sparse warning Signed-off-by: Dave Kleikamp diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index aa1cc7b..6c5485d 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -198,7 +198,7 @@ static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) } } -static inline struct metapage *alloc_metapage(int gfp_mask) +static inline struct metapage *alloc_metapage(unsigned int gfp_mask) { return mempool_alloc(metapage_mempool, gfp_mask); } -- cgit v0.10.2 From 259692bd5a2b2c2d351dd90748ba4126bc2a21b9 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 9 May 2005 10:47:14 -0500 Subject: JFS: Remove redundant kfree() NULL pointer checks kfree() can handle a NULL pointer, don't worry about passing it one. Signed-off-by: Jesper Juhl Signed-off-by: Dave Kleikamp diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 8d2a9ab..30a2bf9 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -70,8 +70,7 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type) if (!IS_ERR(acl)) *p_acl = posix_acl_dup(acl); } - if (value) - kfree(value); + kfree(value); return acl; } @@ -112,8 +111,7 @@ static int jfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) } rc = __jfs_setxattr(inode, ea_name, value, size, 0); out: - if (value) - kfree(value); + kfree(value); if (!rc) { if (*p_acl && (*p_acl != JFS_ACL_NOT_CACHED)) diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 7a9ffd5..6016373 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -946,8 +946,7 @@ int __jfs_setxattr(struct inode *inode, const char *name, const void *value, out: up_write(&JFS_IP(inode)->xattr_sem); - if (os2name) - kfree(os2name); + kfree(os2name); return rc; } @@ -1042,8 +1041,7 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, out: up_read(&JFS_IP(inode)->xattr_sem); - if (os2name) - kfree(os2name); + kfree(os2name); return size; } -- cgit v0.10.2 From 94f19c9a6da1fd3a5958f1a0b44aa340f2596a5b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 24 Mar 2005 12:01:15 +0100 Subject: [ALSA] kill dead code ALSA<-OSS emulation The Coverity checker found this obviously dead code. I'm not sure which of the if (plugin == NULL) is correct - this patch removes the one that couldn't be true. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 6bb3100..6430410 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -663,10 +663,7 @@ static int snd_pcm_plug_playback_channels_mask(snd_pcm_plug_t *plug, bitset_t *dstmask = bs; int err; bitset_one(dstmask, schannels); - if (plugin == NULL) { - bitset_and(client_vmask, dstmask, schannels); - return 0; - } + while (1) { err = plugin->src_channels_mask(plugin, dstmask, &srcmask); if (err < 0) -- cgit v0.10.2 From c301098233bdbaae369bfdd98207db916df8cef2 Mon Sep 17 00:00:00 2001 From: ChenLi Tien Date: Thu, 24 Mar 2005 12:02:54 +0100 Subject: [ALSA] Show currectly selected widget in proc_read for hda driver HDA generic driver During debugging for cm9880 multi-channel playback, I added the * after the currently selected widget, mixer widget doesn't need this but other 3 widget types need it. Signed-off-by: ChenLi Tien Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 4d5db7fa..8c703ff 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -266,13 +266,19 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) if (wid_caps & AC_WCAP_CONN_LIST) { hda_nid_t conn[HDA_MAX_CONNECTIONS]; - int c, conn_len; + int c, conn_len, curr = -1; conn_len = snd_hda_get_connections(codec, nid, conn, HDA_MAX_CONNECTIONS); + if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) + curr = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); snd_iprintf(buffer, " Connection: %d\n", conn_len); snd_iprintf(buffer, " "); - for (c = 0; c < conn_len; c++) + for (c = 0; c < conn_len; c++) { snd_iprintf(buffer, " 0x%02x", conn[c]); + if (c == curr) + snd_iprintf(buffer, "*"); + } snd_iprintf(buffer, "\n"); } } -- cgit v0.10.2 From 36c4dc42249e96f0b0ddc90ca400bcb3981dbc62 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Mar 2005 17:48:30 +0100 Subject: [ALSA] Skip ac97 SPDIF controls CA0106 driver Skip building ac97 SPDIF controls via AC97_SCAP_NO_SPDIF. Clean up the code. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 82533b4..901e42b 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -810,6 +810,7 @@ static int snd_ca0106_ac97(ca0106_t *chip) memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; + ac97.scaps = AC97_SCAP_NO_SPDIF; return snd_ac97_mixer(pbus, &ac97, &chip->ac97); } diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 97bed1b..231ecac 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -620,11 +620,6 @@ int __devinit snd_ca0106_mixer(ca0106_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; - if ((kctl = ctl_find(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT))) != NULL) { - /* already defined by ac97, remove it */ - /* FIXME: or do we need both controls? */ - remove_ctl(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT)); - } if ((kctl = snd_ctl_new1(&snd_ca0106_spdif_control, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) -- cgit v0.10.2 From d05b2817d859a2a2f2c3d5c056b688559fdbcc2b Mon Sep 17 00:00:00 2001 From: ChenLi Tien Date: Thu, 24 Mar 2005 20:47:35 +0100 Subject: [ALSA] fix multi-channel for model==full HDA Codec driver The patch_cm9880.c can't play side/C/B channels from front panel jacks. I fixed it by adding select pin. Signed-off-by: ChenLi Tien Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index b7cc8e4..a44d64e828 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -278,8 +278,10 @@ static struct hda_verb cmi9880_basic_init[] = { { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* port-G for CLFE (rear panel) */ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, /* port-H for side (rear panel) */ { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, /* port-C for line-in (rear panel) */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, /* port-B for mic-in (rear panel) with vref */ @@ -305,6 +307,10 @@ static struct hda_verb cmi9880_allout_init[] = { { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* port-G for CLFE (rear panel) */ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, /* port-C for surround (rear panel) */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* port-B for mic-in (rear panel) with vref */ -- cgit v0.10.2 From 6e4abc40fc125b1dcc2792eacac17606a4d86043 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 26 Mar 2005 19:35:29 +0100 Subject: [ALSA] Adds Capture to P16V chip. EMU10K1/EMU10K2 driver One can select which capture source, but one cannot yet set volumes. Signed-off-by: James Courtier-Dutton diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 43b6786..8221df8 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -83,7 +83,8 @@ #define IPR 0x08 /* Global interrupt pending register */ /* Clear pending interrupts by writing a 1 to */ /* the relevant bits and zero to the other bits */ - +#define IPR_P16V 0x80000000 /* Bit set when the CA0151 P16V chip wishes + to interrupt */ #define IPR_GPIOMSG 0x20000000 /* GPIO message interrupt (RE'd, still not sure which INTE bits enable it) */ @@ -1109,7 +1110,9 @@ struct _snd_emu10k1 { emu10k1_voice_t voices[NUM_G]; emu10k1_voice_t p16v_voices[4]; + emu10k1_voice_t p16v_capture_voice; int p16v_device_offset; + u32 p16v_capture_source; emu10k1_pcm_mixer_t pcm_mixer[32]; emu10k1_pcm_mixer_t efx_pcm_mixer[NUM_EFX_PLAYBACK]; snd_kcontrol_t *ctl_send_routing; diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index b81a7ca..cd8460d 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c @@ -37,7 +37,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) int handled = 0; while ((status = inl(emu->port + IPR)) != 0) { - // printk("irq - status = 0x%x\n", status); + //printk("emu10k1 irq - status = 0x%x\n", status); orig_status = status; handled = 1; if (status & IPR_PCIERROR) { @@ -147,9 +147,36 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); status &= ~IPR_FXDSP; } + if (status & IPR_P16V) { + while ((status2 = inl(emu->port + IPR2)) != 0) { + u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ + emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]); + emu10k1_voice_t *cvoice = &(emu->p16v_capture_voice); + + //printk(KERN_INFO "status2=0x%x\n", status2); + orig_status2 = status2; + if(status2 & mask) { + if(pvoice->use) { + snd_pcm_period_elapsed(pvoice->epcm->substream); + } else { + snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use); + } + } + if(status2 & 0x110000) { + //printk(KERN_INFO "capture int found\n"); + if(cvoice->use) { + //printk(KERN_INFO "capture period_elapsed\n"); + snd_pcm_period_elapsed(cvoice->epcm->substream); + } + } + outl(orig_status2, emu->port + IPR2); /* ack all */ + } + status &= ~IPR_P16V; + } + if (status) { unsigned int bits; - //snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); + snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); //make sure any interrupts we don't handle are disabled: bits = INTE_FXDSPENABLE | INTE_PCIERRORENABLE | @@ -170,20 +197,5 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) } outl(orig_status, emu->port + IPR); /* ack all */ } - if (emu->audigy && emu->revision == 4) { /* P16V */ - while ((status2 = inl(emu->port + IPR2)) != 0) { - u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ - emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]); - orig_status2 = status2; - if(status2 & mask) { - if(pvoice->use) { - snd_pcm_period_elapsed(pvoice->epcm->substream); - } else { - snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use); - } - } - outl(orig_status2, emu->port + IPR2); /* ack all */ - } - } return IRQ_RETVAL(handled); } diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index d03cb2f..dd6ce99 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -132,9 +132,29 @@ static snd_pcm_hardware_t snd_p16v_playback_hw = { .fifo_size = 0, }; +static snd_pcm_hardware_t snd_p16v_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = (32*1024), + .period_bytes_min = 64, + .period_bytes_max = (16*1024), + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0, +}; + + static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime) { - snd_pcm_t *epcm = runtime->private_data; + emu10k1_pcm_t *epcm = runtime->private_data; if (epcm) { //snd_printk("epcm free: %p\n", epcm); @@ -178,15 +198,63 @@ static int snd_p16v_pcm_open_playback_channel(snd_pcm_substream_t *substream, in return 0; } +/* open_capture callback */ +static int snd_p16v_pcm_open_capture_channel(snd_pcm_substream_t *substream, int channel_id) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + emu10k1_voice_t *channel = &(emu->p16v_capture_voice); + emu10k1_pcm_t *epcm; + snd_pcm_runtime_t *runtime = substream->runtime; + int err; + + epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + //snd_printk("epcm kcalloc: %p\n", epcm); + + if (epcm == NULL) + return -ENOMEM; + epcm->emu = emu; + epcm->substream = substream; + //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); + + runtime->private_data = epcm; + runtime->private_free = snd_p16v_pcm_free_substream; + + runtime->hw = snd_p16v_capture_hw; + + channel->emu = emu; + channel->number = channel_id; + + channel->use=1; + //snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use); + //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel); + //channel->interrupt = snd_p16v_pcm_channel_interrupt; + channel->epcm=epcm; + if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + return err; + + return 0; +} + /* close callback */ static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream) { emu10k1_t *emu = snd_pcm_substream_chip(substream); //snd_pcm_runtime_t *runtime = substream->runtime; - //emu10k1_pcm_t *epcm = runtime->private_data; - emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; -/* FIXME: maybe zero others */ + //emu10k1_pcm_t *epcm = runtime->private_data; + emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; + /* FIXME: maybe zero others */ + return 0; +} + +/* close callback */ +static int snd_p16v_pcm_close_capture(snd_pcm_substream_t *substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + //snd_pcm_runtime_t *runtime = substream->runtime; + //emu10k1_pcm_t *epcm = runtime->private_data; + emu->p16v_capture_voice.use=0; + /* FIXME: maybe zero others */ return 0; } @@ -195,36 +263,55 @@ static int snd_p16v_pcm_open_playback_front(snd_pcm_substream_t *substream) return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL); } +static int snd_p16v_pcm_open_capture(snd_pcm_substream_t *substream) +{ + // Only using channel 0 for now, but the card has 2 channels. + return snd_p16v_pcm_open_capture_channel(substream, 0); +} + /* hw_params callback */ static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream, snd_pcm_hw_params_t * hw_params) { int result; - //snd_printk("hw_params alloc: substream=%p\n", substream); result = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - //snd_printk("hw_params alloc: result=%d\n", result); - //dump_stack(); return result; } +/* hw_params callback */ +static int snd_p16v_pcm_hw_params_capture(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t * hw_params) +{ + int result; + result = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + return result; +} + + /* hw_free callback */ static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream) { int result; - //snd_printk("hw_params free: substream=%p\n", substream); result = snd_pcm_lib_free_pages(substream); - //snd_printk("hw_params free: result=%d\n", result); - //dump_stack(); return result; } +/* hw_free callback */ +static int snd_p16v_pcm_hw_free_capture(snd_pcm_substream_t *substream) +{ + int result; + result = snd_pcm_lib_free_pages(substream); + return result; +} + + /* prepare playback callback */ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) { emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - //emu10k1_pcm_t *epcm = runtime->private_data; int channel = substream->pcm->device - emu->p16v_device_offset; u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel)); u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); @@ -253,7 +340,7 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ - for(i=0; i < runtime->periods; i++) { + for(i=0; i < runtime->periods; i++) { table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); table_base[(i*2)+1]=period_size_bytes<<16; } @@ -270,6 +357,23 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) return 0; } +/* prepare capture callback */ +static int snd_p16v_pcm_prepare_capture(snd_pcm_substream_t *substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int channel = substream->pcm->device - emu->p16v_device_offset; + //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); + snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); + snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); + snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes + snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); + //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */ + //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<runtime; + emu10k1_pcm_t *epcm = runtime->private_data; + int channel = 0; + int result = 0; + u32 inte = INTE2_CAPTURE_CH_0_LOOP | INTE2_CAPTURE_CH_0_HALF_LOOP; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + snd_p16v_intr_enable(emu, inte); + snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)|(0x100<running = 1; + break; + case SNDRV_PCM_TRIGGER_STOP: + snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<running = 0; + break; + default: + result = -EINVAL; + break; + } + return result; +} + /* pointer_playback callback */ static snd_pcm_uframes_t snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) @@ -370,6 +504,31 @@ snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) return ptr; } +/* pointer_capture callback */ +static snd_pcm_uframes_t +snd_p16v_pcm_pointer_capture(snd_pcm_substream_t *substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + emu10k1_pcm_t *epcm = runtime->private_data; + snd_pcm_uframes_t ptr, ptr1, ptr2 = 0; + int channel = 0; + + if (!epcm->running) + return 0; + + ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, channel); + ptr2 = bytes_to_frames(runtime, ptr1); + ptr=ptr2; + if (ptr >= runtime->buffer_size) { + ptr -= runtime->buffer_size; + printk("buffer capture limited!\n"); + } + //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate); + + return ptr; +} + /* operators */ static snd_pcm_ops_t snd_p16v_playback_front_ops = { .open = snd_p16v_pcm_open_playback_front, @@ -382,6 +541,18 @@ static snd_pcm_ops_t snd_p16v_playback_front_ops = { .pointer = snd_p16v_pcm_pointer_playback, }; +static snd_pcm_ops_t snd_p16v_capture_ops = { + .open = snd_p16v_pcm_open_capture, + .close = snd_p16v_pcm_close_capture, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_p16v_pcm_hw_params_capture, + .hw_free = snd_p16v_pcm_hw_free_capture, + .prepare = snd_p16v_pcm_prepare_capture, + .trigger = snd_p16v_pcm_trigger_capture, + .pointer = snd_p16v_pcm_pointer_capture, +}; + + int snd_p16v_free(emu10k1_t *chip) { // release the data @@ -405,20 +576,22 @@ int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) snd_pcm_t *pcm; snd_pcm_substream_t *substream; int err; - int capture=0; + int capture=1; //snd_printk("snd_p16v_pcm called. device=%d\n", device); emu->p16v_device_offset = device; if (rpcm) *rpcm = NULL; - //if (device == 0) capture=1; + if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) return err; pcm->private_data = emu; pcm->private_free = snd_p16v_pcm_free; - + // Single playback 8 channel device. + // Single capture 2 channel device. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_p16v_capture_ops); pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; @@ -694,6 +867,56 @@ static snd_kcontrol_new_t snd_p16v_volume_control_spdif_rear = .put = snd_p16v_volume_put_spdif_rear }; +static int snd_p16v_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[8] = { "SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S", "CDIF", "FX", "AC97" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 8; + if (uinfo->value.enumerated.item > 7) + uinfo->value.enumerated.item = 7; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_p16v_capture_source_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->p16v_capture_source; + return 0; +} + +static int snd_p16v_capture_source_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + u32 mask; + u32 source; + + val = ucontrol->value.enumerated.item[0] ; + change = (emu->p16v_capture_source != val); + if (change) { + emu->p16v_capture_source = val; + source = (val << 28) | (val << 24) | (val << 20) | (val << 16); + mask = snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & 0xffff; + snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, source | mask); + } + return change; +} + +static snd_kcontrol_new_t snd_p16v_capture_source __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "HD Capture source", + .info = snd_p16v_capture_source_info, + .get = snd_p16v_capture_source_get, + .put = snd_p16v_capture_source_put +}; int snd_p16v_mixer(emu10k1_t *emu) { int err; @@ -731,6 +954,10 @@ int snd_p16v_mixer(emu10k1_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; + if ((kctl = snd_ctl_new1(&snd_p16v_capture_source, emu)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(card, kctl))) + return err; return 0; } -- cgit v0.10.2 From 65f37647711bf6b0d09b499b9205a33b35ad4ad6 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 26 Mar 2005 22:10:36 +0100 Subject: [ALSA] Add's identification of the SB Live! Platinum [CT4760P] EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c3c96f9..e006887 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -684,6 +684,10 @@ static emu_chip_details_t emu_chip_details[] = { .driver = "EMU10K1", .name = "SB Live 5.1", .emu10k1_chip = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, + .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", + .emu10k1_chip = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .driver = "EMU10K1", .name = "SB Live [Unknown]", .emu10k1_chip = 1, -- cgit v0.10.2 From 56f5ceed002db594500c1d2c2afc875be3d31fb5 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 27 Mar 2005 15:00:54 +0200 Subject: [ALSA] Added identification for the Audigy ES. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index e006887..ff220fc 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -671,6 +671,11 @@ static emu_chip_details_t emu_chip_details[] = { .spk71 = 1, .spdif_bug = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10020052, + .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", + .emu10k2_chip = 1, + .ca0102_chip = 1, + .spdif_bug = 1} , {.vendor = 0x1102, .device = 0x0004, .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", .emu10k2_chip = 1, -- cgit v0.10.2 From a2142674b958d89e0806228a5f6cd22ec379d61d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 29 Mar 2005 16:33:28 +0200 Subject: [ALSA] Fix the detection of resolution of ac97 controls AC97 Codec Fixed the detection of bit resolution of ac97 mixer controls. This will fix the problem with TI ac97 codecs. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 0b024ec..7d2854d 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1072,9 +1072,9 @@ static void check_volume_resolution(ac97_t *ac97, int reg, unsigned char *lo_max unsigned short val; snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8)); val = snd_ac97_read(ac97, reg); - if (! *lo_max && (val & cbit[i])) + if (! *lo_max && (val & 0x7f) == cbit[i]) *lo_max = max[i]; - if (! *hi_max && (val & (cbit[i] << 8))) + if (! *hi_max && ((val >> 8) & 0x7f) == cbit[i]) *hi_max = max[i]; if (*lo_max && *hi_max) break; -- cgit v0.10.2 From 51f633dada113ef724a145bb5b33ec77d1b092f6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Mar 2005 13:49:06 +0200 Subject: [ALSA] Fix memory leak ALSA sequencer Fixed memory leak by the last change of stack reduction. Signed-off-by: Takashi Iwai diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 18247db..57be915 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -414,6 +414,8 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev) if (newclient) synths[card->number] = client; up(®ister_mutex); + kfree(info); + kfree(port); return 0; /* success */ __nomem: -- cgit v0.10.2 From 2b637da5a1bb3c128ecdadea6aee693f6ff3b786 Mon Sep 17 00:00:00 2001 From: Lee Revell Date: Wed, 30 Mar 2005 13:51:18 +0200 Subject: [ALSA] clean up card features EMU10K1/EMU10K2 driver This patch converts the emu10k1 driver to use the card capabilities structure for some more things. Not extensively tested but seems to work. Signed-off-by: Lee Revell Signed-off-by: Takashi Iwai diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 8221df8..b1e8ee8 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1046,6 +1046,7 @@ typedef struct { unsigned char ca0108_chip; /* Audigy 2 Value */ unsigned char ca0151_chip; /* P16V */ unsigned char spk71; /* Has 7.1 speakers */ + unsigned char sblive51; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */ unsigned char spdif_bug; /* Has Spdif phasing bug */ unsigned char ac97_chip; /* Has an AC97 chip */ unsigned char ecard; /* APS EEPROM */ @@ -1057,11 +1058,8 @@ struct _snd_emu10k1 { int irq; unsigned long port; /* I/O port number */ - unsigned int APS: 1, /* APS flag */ - no_ac97: 1, /* no AC'97 */ - tos_link: 1, /* tos link detected */ - rear_ac97: 1, /* rear channels are on AC'97 */ - spk71:1; /* 7.1 configuration (Audigy 2 ZS) */ + unsigned int tos_link: 1, /* tos link detected */ + rear_ac97: 1; /* rear channels are on AC'97 */ const emu_chip_details_t *card_capabilities; /* Contains profile of card capabilities */ unsigned int audigy; /* is Audigy? */ unsigned int revision; /* chip revision */ @@ -1456,7 +1454,6 @@ int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, #endif typedef struct { - unsigned int card; /* card type */ unsigned int internal_tram_size; /* in samples */ unsigned int external_tram_size; /* in samples */ char fxbus_names[16][32]; /* names of FXBUSes */ diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index ff220fc..38be0f1 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -170,7 +170,7 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir) SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); - if (emu->audigy && emu->revision == 4) { /* audigy2 */ + if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Hacks for Alice3 to work independent of haP16V driver */ u32 tmp; @@ -600,7 +600,7 @@ static int snd_emu10k1_free(emu10k1_t *emu) if (emu->port) pci_release_regions(emu->pci); pci_disable_device(emu->pci); - if (emu->audigy && emu->revision == 4) /* P16V */ + if (emu->card_capabilities->ca0151_chip) /* P16V */ snd_p16v_free(emu); kfree(emu); return 0; @@ -612,8 +612,6 @@ static int snd_emu10k1_dev_free(snd_device_t *device) return snd_emu10k1_free(emu); } -/* vendor, device, subsystem, emu10k1_chip, emu10k2_chip, ca0102_chip, ca0108_chip, ca0151_chip, spk71, spdif_bug, ac97_chip, ecard, driver, name */ - static emu_chip_details_t emu_chip_details[] = { /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, @@ -688,15 +686,22 @@ static emu_chip_details_t emu_chip_details[] = { {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, .driver = "EMU10K1", .name = "SB Live 5.1", .emu10k1_chip = 1, - .ac97_chip = 1} , + .ac97_chip = 1, + .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", .emu10k1_chip = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .driver = "EMU10K1", .name = "SB Live [Unknown]", .emu10k1_chip = 1, - .ac97_chip = 1} , + .ac97_chip = 1, + .sblive51 = 1} , { } /* terminator */ }; @@ -747,7 +752,6 @@ int __devinit snd_emu10k1_create(snd_card_t * card, emu->revision = revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model); - emu->card_type = EMU10K1_CARD_CREATIVE; snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model); for (c = emu_chip_details; c->vendor; c++) { @@ -825,15 +829,6 @@ int __devinit snd_emu10k1_create(snd_card_t * card, pci_set_master(pci); - if (c->ecard) { - emu->card_type = EMU10K1_CARD_EMUAPS; - emu->APS = 1; - } - if (! c->ac97_chip) - emu->no_ac97 = 1; - - emu->spk71 = c->spk71; - emu->fx8010.fxbus_mask = 0x303f; if (extin_mask == 0) extin_mask = 0x3fcf; @@ -842,7 +837,7 @@ int __devinit snd_emu10k1_create(snd_card_t * card, emu->fx8010.extin_mask = extin_mask; emu->fx8010.extout_mask = extout_mask; - if (emu->APS) { + if (emu->card_capabilities->ecard) { if ((err = snd_emu10k1_ecard_init(emu)) < 0) { snd_emu10k1_free(emu); return err; diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index b9fa2e8..0529fb2 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1077,7 +1077,7 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) gpr += 2; /* PCM Side Playback (independent from stereo mix) */ - if (emu->spk71) { + if (emu->card_capabilities->spk71) { A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE)); A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100); @@ -1145,14 +1145,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L); A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "CD Playback Volume" : "Audigy CD Playback Volume", + emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume", gpr, 0); gpr += 2; /* Audigy CD Capture Volume */ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L); A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "CD Capture Volume" : "Audigy CD Capture Volume", + emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume", gpr, 0); gpr += 2; @@ -1171,14 +1171,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L); A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "Line Playback Volume" : "Line2 Playback Volume", + emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume", gpr, 0); gpr += 2; /* Line2 Capture Volume */ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L); A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "Line Capture Volume" : "Line2 Capture Volume", + emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume", gpr, 0); gpr += 2; @@ -1197,14 +1197,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L); A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "Aux Playback Volume" : "Aux2 Playback Volume", + emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume", gpr, 0); gpr += 2; /* Aux2 Capture Volume */ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L); A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "Aux Capture Volume" : "Aux2 Capture Volume", + emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume", gpr, 0); gpr += 2; @@ -1232,7 +1232,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0); gpr++; - if (emu->spk71) { + if (emu->card_capabilities->spk71) { /* Stereo Mix Side Playback */ A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix)); A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1)); @@ -1266,7 +1266,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), A_GPR(playback + 3), A_C_00000000, A_C_00000000); /* rear right */ A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */ A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */ - if (emu->spk71) { + if (emu->card_capabilities->spk71) { A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 6), A_GPR(playback + 6), A_C_00000000, A_C_00000000); /* side left */ A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 7), A_GPR(playback + 7), A_C_00000000, A_C_00000000); /* side right */ } @@ -1359,7 +1359,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); - if (emu->spk71) + if (emu->card_capabilities->spk71) A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS); /* headphone */ @@ -1982,22 +1982,27 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu) OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000); /* EFX capture - capture the 16 EXTINS */ - OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0)); - OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1)); - OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2)); - OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3)); - /* Dont connect anything to FXBUS2 1 and 2. These are shared with - * Center/LFE on the SBLive 5.1. The kX driver only changes the - * routing when it detects an SBLive 5.1. - * - * Since only 14 of the 16 EXTINs are used, this is not a big problem. - * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture - * 0 and 3, then the rest of the EXTINs to the corresponding FX capture - * channel. - */ - for (z = 4; z < 14; z++) { - OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); + if (emu->card_capabilities->sblive51) { + /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER + * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording. + * + * Since only 14 of the 16 EXTINs are used, this is not a big problem. + * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture + * 0 and 3, then the rest of the EXTINs to the corresponding FX capture + * channel. Multitrack recorders will still see the center/lfe output signal + * on the second and third channels. + */ + OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0)); + OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1)); + OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2)); + OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3)); + for (z = 4; z < 14; z++) + OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); + } else { + for (z = 0; z < 16; z++) + OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); } + if (gpr > tmp) { snd_BUG(); @@ -2128,7 +2133,6 @@ static int snd_emu10k1_fx8010_info(emu10k1_t *emu, emu10k1_fx8010_info_t *info) int res; memset(info, 0, sizeof(info)); - info->card = emu->card_type; info->internal_tram_size = emu->fx8010.itram_size; info->external_tram_size = emu->fx8010.etram_pages.bytes / 2; fxbus = fxbuses; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 044663d..d0b2965 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -791,7 +791,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) NULL }; - if (!emu->no_ac97) { + if (emu->card_capabilities->ac97_chip) { ac97_bus_t *pbus; ac97_template_t ac97; static ac97_bus_ops_t ops = { @@ -833,7 +833,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) for (; *c; c++) remove_ctl(card, *c); } else { - if (emu->APS) + if (emu->card_capabilities->ecard) strcpy(emu->card->mixername, "EMU APS"); else if (emu->audigy) strcpy(emu->card->mixername, "SB Audigy"); @@ -918,7 +918,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) mix->attn[0] = 0xffff; } - if (! emu->APS) { /* FIXME: APS has these controls? */ + if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ /* sb live! and audigy */ if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) return -ENOMEM; @@ -939,14 +939,14 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; - } else if (! emu->APS) { + } else if (! emu->card_capabilities->ecard) { /* sb live! */ if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; } - if (emu->audigy && emu->revision == 4) { /* P16V */ + if (emu->card_capabilities->ca0151_chip) { /* P16V */ if ((err = snd_p16v_mixer(emu))) return err; } diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index d990d5e..732d17d 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -182,7 +182,7 @@ static void snd_emu10k1_proc_read(snd_info_entry_t *entry, snd_iprintf(buffer, "EMU10K1\n\n"); snd_iprintf(buffer, "Card : %s\n", - emu->audigy ? "Audigy" : (emu->APS ? "EMU APS" : "Creative")); + emu->audigy ? "Audigy" : (emu->card_capabilities->ecard ? "EMU APS" : "Creative")); snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size); snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", (int)emu->fx8010.etram_pages.bytes / 2); snd_iprintf(buffer, "\n"); -- cgit v0.10.2 From 9c220a31fd2f609ba55250a75d85ca795051a482 Mon Sep 17 00:00:00 2001 From: Lee Revell Date: Wed, 30 Mar 2005 14:04:34 +0200 Subject: [ALSA] some docs for the new emu10k1 multichannel functionality Documentation Not complete, or even spell checked, but in case I don't get a chance to work on it again before 1.0.9, here is what i have so far. It should go in alsa-kernel/Documentation/emu10k1-jack.txt. Signed-off-by: Lee Revell Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/emu10k1-jack.txt b/Documentation/sound/alsa/emu10k1-jack.txt new file mode 100644 index 0000000..751d450 --- /dev/null +++ b/Documentation/sound/alsa/emu10k1-jack.txt @@ -0,0 +1,74 @@ +This document is a guide to using the emu10k1 based devices with JACK for low +latency, multichannel recording functionality. All of my recent work to allow +Linux users to use the full capabilities of their hardware has been inspired +by the kX Project. Without their work I never would have discovered the true +power of this hardware. + + http://www.kxproject.com + - Lee Revell, 2005.03.30 + +Low latency, multichannel audio with JACK and the emu10k1/emu10k2 +----------------------------------------------------------------- + +Until recently, emu10k1 users on Linux did not have access to the same low +latency, multichannel features offered by the "kX ASIO" feature of their +Windows driver. As of ALSA 1.0.9 this is no more! + +For those unfamiliar with kX ASIO, this consists of 16 capture and 16 playback +channels. With a post 2.6.9 Linux kernel, latencies down to 64 (1.33 ms) or +even 32 (0.66ms) frames should work well. + +The configuration is slightly more involved than on Windows, as you have to +select the correct device for JACK to use. Actually, for qjackctl users it's +fairly self explanatory - select Duplex, then for capture and playback select +the multichannel devices, set the in and out channels to 16, and the sample +rate to 48000Hz. The command line looks like this: + +/usr/local/bin/jackd -R -dalsa -r48000 -p64 -n2 -D -Chw:0,2 -Phw:0,3 -S + +This will give you 16 input ports and 16 output ports. + +The 16 output ports map onto the 16 FX buses (or the first 16 of 64, for the +Audigy). The mapping from FX bus to physical output is described in +SB-Live-mixer.txt (or Audigy-mixer.txt). + +The 16 input ports are connected to the 16 physical inputs. Contrary to +popular belief, all emu10k1 cards are multichannel cards. Which of these +input channels have physical inputs connected to them depends on the card +model. Trial and error is highly recommended; the pinout diagrams +for the card have been reverse engineered by some enterprising kX users and are +available on the internet. Meterbridge is helpful here, and the kX forums are +packed with useful information. + +Each input port will either correspond to a digital (SPDIF) input, an analog +input, or nothing. The one exception is the SBLive! 5.1. On these devices, +the second and third input ports are wired to the center/LFE output. You will +still see 16 capture channels, but only 14 are available for recording inputs. + +This chart, borrowed from kxfxlib/da_asio51.cpp, describes the mapping of JACK +ports to FXBUS2 (multitrack recording input) and EXTOUT (physical output) +channels. + +/*JACK (& ASIO) mappings on 10k1 5.1 SBLive cards: +-------------------------------------------- +JACK Epilog FXBUS2(nr) +-------------------------------------------- +capture_1 asio14 FXBUS2(0xe) +capture_2 asio15 FXBUS2(0xf) +capture_3 asio0 FXBUS2(0x0) +~capture_4 Center EXTOUT(0x11) // mapped to by Center +~capture_5 LFE EXTOUT(0x12) // mapped to by LFE +capture_6 asio3 FXBUS2(0x3) +capture_7 asio4 FXBUS2(0x4) +capture_8 asio5 FXBUS2(0x5) +capture_9 asio6 FXBUS2(0x6) +capture_10 asio7 FXBUS2(0x7) +capture_11 asio8 FXBUS2(0x8) +capture_12 asio9 FXBUS2(0x9) +capture_13 asio10 FXBUS2(0xa) +capture_14 asio11 FXBUS2(0xb) +capture_15 asio12 FXBUS2(0xc) +capture_16 asio13 FXBUS2(0xd) +*/ + +TODO: describe use of ld10k1/qlo10k1 in conjunction with JACK -- cgit v0.10.2 From aec72e0a4be407fb69fbee812cf0028d62e75152 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Mar 2005 14:22:25 +0200 Subject: [ALSA] Use old default id strings for compatibility EMU10K1/EMU10K2 driver Use expliciitly the old default id strings for backward compatibility. This will make 'alsactl restore' working again. Signed-off-by: Takashi Iwai diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index b1e8ee8..6647919 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1050,8 +1050,9 @@ typedef struct { unsigned char spdif_bug; /* Has Spdif phasing bug */ unsigned char ac97_chip; /* Has an AC97 chip */ unsigned char ecard; /* APS EEPROM */ - char * driver; - char * name; + const char *driver; + const char *name; + const char *id; /* for backward compatibility - can be NULL if not needed */ } emu_chip_details_t; struct _snd_emu10k1 { diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 38be0f1..a2fa501 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -616,15 +616,18 @@ static emu_chip_details_t emu_chip_details[] = { /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1} , {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, @@ -633,6 +636,7 @@ static emu_chip_details_t emu_chip_details[] = { .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102, .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, @@ -641,6 +645,7 @@ static emu_chip_details_t emu_chip_details[] = { .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102, .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, @@ -649,6 +654,7 @@ static emu_chip_details_t emu_chip_details[] = { .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102, .driver = "Audigy2", .name = "Audigy 2 [SB0240]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, @@ -657,12 +663,14 @@ static emu_chip_details_t emu_chip_details[] = { .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, .driver = "Audigy2", .name = "Audigy 2 EX [1005]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, .spdif_bug = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, @@ -671,34 +679,41 @@ static emu_chip_details_t emu_chip_details[] = { .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10020052, .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", + .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .spdif_bug = 1} , {.vendor = 0x1102, .device = 0x0004, .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", + .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .spdif_bug = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, .driver = "EMU10K1", .name = "E-mu APS [4001]", + .id = "APS", .emu10k1_chip = 1, .ecard = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, .driver = "EMU10K1", .name = "SB Live 5.1", + .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", + .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102, .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", + .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .driver = "EMU10K1", .name = "SB Live [Unknown]", + .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , @@ -772,6 +787,9 @@ int __devinit snd_emu10k1_create(snd_card_t * card, else snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial); + if (!*card->id && c->id) + strlcpy(card->id, c->id, sizeof(card->id)); + is_audigy = emu->audigy = c->emu10k2_chip; /* set the DMA transfer mask */ -- cgit v0.10.2 From 85a655d66b4d1672c7c6fee31297837556585f6b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Mar 2005 14:40:25 +0200 Subject: [ALSA] Fix the default id of multiple cards EMU10K1/EMU10K2 driver Fixed the default id string in case identical multiple cards exist. Signed-off-by: Takashi Iwai diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index a2fa501..c51a8ae 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -787,8 +787,22 @@ int __devinit snd_emu10k1_create(snd_card_t * card, else snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial); - if (!*card->id && c->id) + if (!*card->id && c->id) { + int i, n = 0; strlcpy(card->id, c->id, sizeof(card->id)); + for (;;) { + for (i = 0; i < snd_ecards_limit; i++) { + if (snd_cards[i] && !strcmp(snd_cards[i]->id, card->id)) + break; + } + if (i >= snd_ecards_limit) + break; + n++; + if (n >= SNDRV_CARDS) + break; + snprintf(card->id, sizeof(card->id), "%s_%d", c->id, n); + } + } is_audigy = emu->audigy = c->emu10k2_chip; -- cgit v0.10.2 From c1ab5d59a0ff0981828a169886b10045dfdf64c6 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 30 Mar 2005 16:22:01 +0200 Subject: [ALSA] usb-audio - allow USB MIDI quirks to specify endpoints explicitly USB generic driver This patch reintroduces the check for endpoint numbers that are specified explicitly in the quirk structure. This check was accidentally dropped in the last rewrite of snd_usbmidi_detect_endpoints(). Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 5d32857..600d990 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1229,6 +1229,9 @@ static int snd_usbmidi_detect_endpoints(snd_usb_midi_t* umidi, if (le16_to_cpu(umidi->chip->dev->descriptor.idVendor) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); + if (endpoint[0].out_ep || endpoint[0].in_ep) + return 0; + intf = umidi->iface; if (!intf || intf->num_altsetting < 1) return -ENOENT; -- cgit v0.10.2 From 2668907a825702ba9c0e603f160a993b034572f5 Mon Sep 17 00:00:00 2001 From: Peter Zubaj Date: Fri, 1 Apr 2005 11:15:07 +0200 Subject: [ALSA] Audigy SB0090 identification EMU10K1/EMU10K2 driver This add identification of Audigy 1 model SB0090 and fixes problems with ac97 codec (mic not working). Signed-off-by: Peter Zubaj Signed-off-by: Takashi Iwai diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c51a8ae..a3a1a10 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -619,12 +619,14 @@ static emu_chip_details_t emu_chip_details[] = { .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, - .spk71 = 1} , + .spk71 = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", .id = "Audigy2", .emu10k2_chip = 1, - .ca0108_chip = 1} , + .ca0108_chip = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", .id = "Audigy2", @@ -682,13 +684,21 @@ static emu_chip_details_t emu_chip_details[] = { .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, - .spdif_bug = 1} , + .spdif_bug = 1, + .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102, + .driver = "Audigy", .name = "Audigy 1 [SB0090]", + .id = "Audigy", + .emu10k2_chip = 1, + .ca0102_chip = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, - .spdif_bug = 1} , + .spdif_bug = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, .driver = "EMU10K1", .name = "E-mu APS [4001]", .id = "APS", -- cgit v0.10.2 From 54ab87e6f53099b9a480b56149fa621c3132c076 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 1 Apr 2005 13:14:14 +0200 Subject: [ALSA] Add mixer map for Sound Blaster MP3+ USB generic driver Added the mixer mapping for Sound Blaster MP3+ by Pavel Mihaylov Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index c69b4b0..1e994c9 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -91,6 +91,33 @@ static struct usbmix_name_map extigy_map[] = { { 0 } /* terminator */ }; +/* Sound Blaster MP3+ controls mapping + * The default mixer channels have totally misleading names, + * e.g. no Master and fake PCM volume + * Pavel Mihaylov + */ +static struct usbmix_name_map mp3plus_map[] = { + /* 1: IT pcm */ + /* 2: IT mic */ + /* 3: IT line */ + /* 4: IT digital in */ + /* 5: OT digital out */ + /* 6: OT speaker */ + /* 7: OT pcm capture */ + { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ + /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ + { 9, "Master Playback" }, /* FU, default Speaker 1 */ + /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ + /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ + { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ + { 11, "Line Capture" }, /* FU, default PCM Capture */ + { 12, "Digital In Playback" }, /* FU, default PCM 1 */ + /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ + { 14, "Line Playback" }, /* FU, default Speaker */ + /* 15: MU */ + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -128,6 +155,7 @@ static struct usbmix_name_map justlink_map[] = { static struct usbmix_ctl_map usbmix_ctl_maps[] = { { 0x41e, 0x3000, extigy_map, 1 }, + { 0x41e, 0x3010, mp3plus_map, 0 }, { 0x8bb, 0x2702, linex_map, 1 }, { 0xc45, 0x1158, justlink_map, 0 }, { 0 } /* terminator */ -- cgit v0.10.2 From c1935b4d6edf1c4d78bf660992d00b2d8fcb9b59 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 4 Apr 2005 16:44:58 +0200 Subject: [ALSA] timer - added tread semaphore Timer Midlevel Signed-off-by: Jaroslav Kysela diff --git a/sound/core/timer.c b/sound/core/timer.c index fa762ca..be6d37a 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -69,6 +69,7 @@ typedef struct { struct timespec tstamp; /* trigger tstamp */ wait_queue_head_t qchange_sleep; struct fasync_struct *fasync; + struct semaphore tread_sem; } snd_timer_user_t; /* list of timers */ @@ -1208,6 +1209,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) return -ENOMEM; spin_lock_init(&tu->qlock); init_waitqueue_head(&tu->qchange_sleep); + init_MUTEX(&tu->tread_sem); tu->ticks = 1; tu->queue_size = 128; tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); @@ -1454,18 +1456,23 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * snd_timer_user_t *tu; snd_timer_select_t tselect; char str[32]; - int err; + int err = 0; tu = file->private_data; - if (tu->timeri) + down(&tu->tread_sem); + if (tu->timeri) { snd_timer_close(tu->timeri); - if (copy_from_user(&tselect, _tselect, sizeof(tselect))) - return -EFAULT; + tu->timeri = NULL; + } + if (copy_from_user(&tselect, _tselect, sizeof(tselect))) { + err = -EFAULT; + goto __err; + } sprintf(str, "application %i", current->pid); if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0) - return err; + goto __err; if (tu->queue) { kfree(tu->queue); @@ -1477,23 +1484,27 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * } if (tu->tread) { tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); - if (tu->tqueue == NULL) { - snd_timer_close(tu->timeri); - return -ENOMEM; - } + if (tu->tqueue == NULL) + err = -ENOMEM; } else { tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); - if (tu->queue == NULL) { - snd_timer_close(tu->timeri); - return -ENOMEM; - } + if (tu->queue == NULL) + err = -ENOMEM; } - tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; - tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; - tu->timeri->ccallback = snd_timer_user_ccallback; - tu->timeri->callback_data = (void *)tu; - return 0; + if (err < 0) { + snd_timer_close(tu->timeri); + tu->timeri = NULL; + } else { + tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; + tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; + tu->timeri->ccallback = snd_timer_user_ccallback; + tu->timeri->callback_data = (void *)tu; + } + + __err: + up(&tu->tread_sem); + return err; } static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) @@ -1685,11 +1696,17 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l { int xarg; - if (tu->timeri) /* too late */ + down(&tu->tread_sem); + if (tu->timeri) { /* too late */ + up(&tu->tread_sem); return -EBUSY; - if (get_user(xarg, p)) + } + if (get_user(xarg, p)) { + up(&tu->tread_sem); return -EFAULT; + } tu->tread = xarg ? 1 : 0; + up(&tu->tread_sem); return 0; } case SNDRV_TIMER_IOCTL_GINFO: -- cgit v0.10.2 From 0aa0d387877e8e6408d316aaee1ea84f8e1fb447 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 6 Apr 2005 09:43:59 +0200 Subject: [ALSA] virmidi - fix ioctl parameter passing when creating seq port ALSA sequencer The last change to reduce stack usage did not adjust the parameter to SNDRV_SEQ_IOCTL_CREATE_PORT which resulted in passing the address of the pointer instead of the structure. Signed-off-by: Clemens Ladisch diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 6b4e630..1274ab4 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -405,7 +405,7 @@ static int snd_virmidi_dev_attach_seq(snd_virmidi_dev_t *rdev) pcallbacks.unuse = snd_virmidi_unuse; pcallbacks.event_input = snd_virmidi_event_input; pinfo->kernel = &pcallbacks; - err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo); + err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, pinfo); if (err < 0) { snd_seq_delete_kernel_client(client); rdev->client = -1; -- cgit v0.10.2 From 5af4c83375cba113fb7e1ed57024a5442ca5060e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 6 Apr 2005 09:47:02 +0200 Subject: [ALSA] usb-audio - BOSS GS-10 PCM support USB generic driver This patch adds quirks to support 24-bit PCM I/O in the 'Advanced Driver' mode of the BOSS GS-10. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 88bbd94..00781fe 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -609,15 +609,33 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* + * This quirk is for the "Advanced Driver" mode. If off, the GS-10 + * has ID 0x003c and is standard compliant, but has only 16-bit PCM + * and no MIDI. + */ USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "BOSS", .product_name = "GS-10", - .ifnum = 3, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0003, - .in_cables = 0x0003 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 3, + .type = QUIRK_MIDI_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } } } }, -- cgit v0.10.2 From bdaed50292bea3e2b20c68c2ffe9dbde7c0d6910 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 Apr 2005 15:48:42 +0200 Subject: [ALSA] Check revision for the proper detection of audigy 2 EMU10K1/EMU10K2 driver Check ther revision to detect non-listed audigy 2 boards. Signed-off-by: Takashi Iwai diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 6647919..f5babd3 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1040,6 +1040,7 @@ typedef struct { u32 vendor; u32 device; u32 subsystem; + unsigned char revision; unsigned char emu10k1_chip; /* Original SB Live. Not SB Live 24bit. */ unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */ unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index a3a1a10..c6d53b4 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -679,6 +679,14 @@ static emu_chip_details_t emu_chip_details[] = { .spk71 = 1, .spdif_bug = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, + .driver = "Audigy2", .name = "Audigy 2 [Unknown]", + .id = "Audigy2", + .emu10k2_chip = 1, + .ca0102_chip = 1, + .ca0151_chip = 1, + .spdif_bug = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10020052, .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", .id = "Audigy", @@ -693,11 +701,10 @@ static emu_chip_details_t emu_chip_details[] = { .ca0102_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, - .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", + .driver = "Audigy", .name = "Audigy 1 [Unknown]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, - .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, .driver = "EMU10K1", .name = "E-mu APS [4001]", @@ -781,8 +788,11 @@ int __devinit snd_emu10k1_create(snd_card_t * card, for (c = emu_chip_details; c->vendor; c++) { if (c->vendor == pci->vendor && c->device == pci->device) { - if (c->subsystem == emu->serial) break; - if (c->subsystem == 0) break; + if (c->subsystem && c->subsystem != emu->serial) + continue; + if (c->revision && c->revision != emu->revision) + continue; + break; } } if (c->vendor == 0) { -- cgit v0.10.2 From 55911694bf5edf15328dc6558fa3f432d52015ee Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 Apr 2005 15:50:13 +0200 Subject: [ALSA] Remove unused variables AC97 Codec Removed unused variables (the old control definitions). Signed-off-by: Takashi Iwai diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 7d2854d..4ece205 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -658,11 +658,6 @@ AC97_SINGLE("LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 1, 1), AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1) }; -static const snd_kcontrol_new_t snd_ac97_controls_surround[2] = { -AC97_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), -AC97_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), -}; - static const snd_kcontrol_new_t snd_ac97_control_eapd = AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1); -- cgit v0.10.2 From 5f0dccf8500b0cc2ff247f626bc249bc184fd184 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 Apr 2005 15:53:20 +0200 Subject: [ALSA] Add CM9780 support, fix CM9761 SPDIF AC97 Codec - Added CM9780 patch - Fix the SPDIF support on CM9761/CM9780 - Allow the generic enum callback to pass any number (not power of 2) as the value mask Signed-off-by: Takashi Iwai diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 4ece205..61549b1 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -120,6 +120,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { { 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, { 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL }, { 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, +{ 0x434d4969, 0xffffffff, "CMI9780", patch_cm9780, NULL }, { 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL }, { 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL }, { 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL }, @@ -462,12 +463,14 @@ int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; - unsigned short val; + unsigned short val, bitmask; + for (bitmask = 1; bitmask > e->mask; bitmask <<= 1) + ; val = snd_ac97_read_cache(ac97, e->reg); - ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (e->mask - 1); + ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); if (e->shift_l != e->shift_r) - ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (e->mask - 1); + ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (bitmask - 1); return 0; } @@ -477,17 +480,19 @@ int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u ac97_t *ac97 = snd_kcontrol_chip(kcontrol); struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; unsigned short val; - unsigned short mask; + unsigned short mask, bitmask; + for (bitmask = 1; bitmask > e->mask; bitmask <<= 1) + ; if (ucontrol->value.enumerated.item[0] > e->mask - 1) return -EINVAL; val = ucontrol->value.enumerated.item[0] << e->shift_l; - mask = (e->mask - 1) << e->shift_l; + mask = (bitmask - 1) << e->shift_l; if (e->shift_l != e->shift_r) { if (ucontrol->value.enumerated.item[1] > e->mask - 1) return -EINVAL; val |= ucontrol->value.enumerated.item[1] << e->shift_r; - mask |= (e->mask - 1) << e->shift_r; + mask |= (bitmask - 1) << e->shift_r; } return snd_ac97_update_bits(ac97, e->reg, mask, val); } diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 13c34a5..473840d 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2087,12 +2087,13 @@ int patch_cm9739(ac97_t * ac97) } #define AC97_CM9761_MULTI_CHAN 0x64 +#define AC97_CM9761_FUNC 0x66 #define AC97_CM9761_SPDIF_CTRL 0x6c static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x0400) + if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x0400) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; @@ -2106,14 +2107,14 @@ static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_el { 0x0008, 0x0400 }, /* off, on */ { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ }; - return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x0408, + return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); } static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) + if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x1000) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; @@ -2129,7 +2130,7 @@ static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_ele { 0x2000, 0x1880 }, /* off, on */ { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ }; - return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3880, + return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); } @@ -2152,6 +2153,70 @@ static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { }, }; +static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item > 2) + uinfo->value.enumerated.item = 2; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int cm9761_spdif_out_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + if (ac97->regs[AC97_CM9761_FUNC] & 0x1) + ucontrol->value.enumerated.item[0] = 2; /* SPDIF-loopback */ + else if (ac97->regs[AC97_CM9761_SPDIF_CTRL] & 0x2) + ucontrol->value.enumerated.item[0] = 1; /* ADC loopback */ + else + ucontrol->value.enumerated.item[0] = 0; /* AC-link */ + return 0; +} + +static int cm9761_spdif_out_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + if (ucontrol->value.enumerated.item[0] == 2) + return snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0x1); + snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0); + return snd_ac97_update_bits(ac97, AC97_CM9761_SPDIF_CTRL, 0x2, + ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0); +} + +static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" }; +static const struct ac97_enum cm9761_dac_clock_enum = + AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock); + +static const snd_kcontrol_new_t snd_ac97_cm9761_controls_spdif[] = { + { /* BIT 1: SPDIFS */ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", + .info = cm9761_spdif_out_source_info, + .get = cm9761_spdif_out_source_get, + .put = cm9761_spdif_out_source_put, + }, + /* BIT 2: IG_SPIV */ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9761_SPDIF_CTRL, 2, 1, 0), + /* BIT 3: SPI2F */ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9761_SPDIF_CTRL, 3, 1, 0), + /* BIT 4: SPI2SDI */ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9761_SPDIF_CTRL, 4, 1, 0), + /* BIT 9-10: DAC_CTL */ + AC97_ENUM("DAC Clock Source", cm9761_dac_clock_enum), +}; + +static int patch_cm9761_post_spdif(ac97_t * ac97) +{ + return patch_build_controls(ac97, snd_ac97_cm9761_controls_spdif, ARRAY_SIZE(snd_ac97_cm9761_controls_spdif)); +} + static int patch_cm9761_specific(ac97_t * ac97) { return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); @@ -2159,7 +2224,7 @@ static int patch_cm9761_specific(ac97_t * ac97) static struct snd_ac97_build_ops patch_cm9761_ops = { .build_specific = patch_cm9761_specific, - .build_post_spdif = patch_cm9739_post_spdif /* hope it's identical... */ + .build_post_spdif = patch_cm9761_post_spdif }; int patch_cm9761(ac97_t *ac97) @@ -2193,24 +2258,25 @@ int patch_cm9761(ac97_t *ac97) /* to be sure: we overwrite the ext status bits */ snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0); /* Don't set 0x0200 here. This results in the silent analog output */ - snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0009); + snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0001); /* enable spdif-in */ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ /* set-up multi channel */ /* bit 15: pc master beep off - * bit 14: ?? + * bit 14: pin47 = EAPD/SPDIF * bit 13: vref ctl [= cm9739] - * bit 12: center/mic [= cm9739] (reverted on rev B) - * bit 11: ?? (mic/center/lfe) (reverted on rev B) - * bit 10: suddound/line [= cm9739] - * bit 9: mix 2 surround - * bit 8: ? - * bit 7: ?? (mic/center/lfe) - * bit 4: ?? (front) - * bit 3: ?? (line-in/rear share) (revereted with rev B) - * bit 2: ?? (surround) - * bit 1: front mic - * bit 0: mic boost + * bit 12: CLFE control (reverted on rev B) + * bit 11: Mic/center share (reverted on rev B) + * bit 10: suddound/line share + * bit 9: Analog-in mix -> surround + * bit 8: Analog-in mix -> CLFE + * bit 7: Mic/LFE share (mic/center/lfe) + * bit 5: vref select (9761A) + * bit 4: front control + * bit 3: surround control (revereted with rev B) + * bit 2: front mic + * bit 1: stereo mic + * bit 0: mic boost level (0=20dB, 1=30dB) */ #if 0 @@ -2230,6 +2296,47 @@ int patch_cm9761(ac97_t *ac97) return 0; } +#define AC97_CM9780_SIDE 0x60 +#define AC97_CM9780_JACK 0x62 +#define AC97_CM9780_MIXER 0x64 +#define AC97_CM9780_MULTI_CHAN 0x66 +#define AC97_CM9780_SPDIF 0x6c + +static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" }; +static const struct ac97_enum cm9780_ch_select_enum = + AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select); +static const snd_kcontrol_new_t cm9780_controls[] = { + AC97_DOUBLE("Side Playback Switch", AC97_CM9780_SIDE, 15, 7, 1, 1), + AC97_DOUBLE("Side Playback Volume", AC97_CM9780_SIDE, 8, 0, 31, 0), + AC97_ENUM("Side Playback Route", cm9780_ch_select_enum), +}; + +static int patch_cm9780_specific(ac97_t *ac97) +{ + return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls)); +} + +static struct snd_ac97_build_ops patch_cm9780_ops = { + .build_specific = patch_cm9780_specific, + .build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */ +}; + +int patch_cm9780(ac97_t *ac97) +{ + unsigned short val; + + ac97->build_ops = &patch_cm9780_ops; + + /* enable spdif */ + if (ac97->ext_id & AC97_EI_SPDIF) { + ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ + val = snd_ac97_read(ac97, AC97_CM9780_SPDIF); + val |= 0x1; /* SPDI_EN */ + snd_ac97_write_cache(ac97, AC97_CM9780_SPDIF, val); + } + + return 0; +} /* * VIA VT1616 codec diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 6db51c9..7b7377d 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h @@ -54,6 +54,7 @@ int patch_alc850(ac97_t * ac97); int patch_cm9738(ac97_t * ac97); int patch_cm9739(ac97_t * ac97); int patch_cm9761(ac97_t * ac97); +int patch_cm9780(ac97_t * ac97); int patch_vt1616(ac97_t * ac97); int patch_it2646(ac97_t * ac97); int mpatch_si3036(ac97_t * ac97); -- cgit v0.10.2 From 2c56c47f678b0388290686d5a0988d8806ffe5cc Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Thu, 7 Apr 2005 20:21:21 +0200 Subject: [ALSA] Fix 'semaphore is not ready' problem with snd-intel8x0m Intel8x0-modem driver With some intel based ac97 modems codec access semaphore is not cleared after 0x54 AC97 register (GPIO_STATUS) reads. This may causes problems with newly applied modem mixer (Off-hook switch) and in other cases. Signed-off-by: Sasha Khapyorsky Signed-off-by: Takashi Iwai diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 67da096..f9972b2 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -500,6 +500,8 @@ static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, res = 0xffff; } } + if (reg == AC97_GPIO_STATUS) + iagetword(chip, 0); /* clear semaphore */ return res; } -- cgit v0.10.2 From 8e8311b0ac4dc8a2cf317e122a6f7dc4467e3254 Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Thu, 7 Apr 2005 20:22:58 +0200 Subject: [ALSA] Fix MC97 codec initialization AC97 Codec This (especially 12000 -> 8000 sample rate replace) fix popular 'MC97 converters.. not ready' error with modem codecs initializations. Signed-off-by: Sasha Khapyorsky Signed-off-by: Takashi Iwai diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 61549b1..ab7114c 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1964,21 +1964,21 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) /* note: it's important to set the rate at first */ tmp = AC97_MEA_GPIO; if (ac97->ext_mid & AC97_MEI_LINE1) { - snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000); + snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 8000); tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; } if (ac97->ext_mid & AC97_MEI_LINE2) { - snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000); + snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 8000); tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; } if (ac97->ext_mid & AC97_MEI_HANDSET) { - snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000); + snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 8000); tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; } - snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0); udelay(100); /* nothing should be in powerdown mode */ - snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0); end_time = jiffies + (HZ / 10); do { if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) -- cgit v0.10.2 From 23fea4dad67a665e8d359dbb39180422385f1dcc Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Thu, 7 Apr 2005 20:23:58 +0200 Subject: [ALSA] MC97 registers reset AC97 Codec Separated ac97 registers reset for audio and modem (or both) as recommended in AC97 spec. Signed-off-by: Sasha Khapyorsky Signed-off-by: Takashi Iwai diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index ab7114c..1ad7f83 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1872,7 +1872,11 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) goto __access_ok; } - snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */ + /* reset to defaults */ + if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO)) + snd_ac97_write(ac97, AC97_RESET, 0); + if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM)) + snd_ac97_write(ac97, AC97_EXTENDED_MID, 0); if (bus->ops->wait) bus->ops->wait(ac97); else { -- cgit v0.10.2 From 22e0732e59b3482bb2f068bfe911c532767e5974 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 8 Apr 2005 08:25:23 +0200 Subject: [ALSA] virmidi - fix ioctl parameter passing when setting client name ALSA sequencer The last change to reduce stack usage did not adjust the parameter to SNDRV_SEQ_IOCTL_SET_CLIENT_IOCTL which resulted in passing the address of the pointer instead of the structure. Signed-off-by: Clemens Ladisch diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 1274ab4..58c56a1 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -384,7 +384,7 @@ static int snd_virmidi_dev_attach_seq(snd_virmidi_dev_t *rdev) info->client = client; info->type = KERNEL_CLIENT; sprintf(info->name, "%s %d-%d", rdev->rmidi->name, rdev->card->number, rdev->device); - snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &info); + snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info); /* create a port */ memset(pinfo, 0, sizeof(*pinfo)); -- cgit v0.10.2 From f953eff29c1ea4c744afe3d50ff5ca33b44efcd2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Apr 2005 15:05:13 +0200 Subject: [ALSA] choose multi-channel jacks automatically HDA Codec driver Patch by C.L. Tien : The patch makes cm9880 to choose multi-channel jacks automatically. 1. I found the current code has basic_init, which already includes necessary controls for 6-stack initialization, so I don't need another model. 2. I add a new model 'auto' to let the driver find a. if there are option real panel/front panel, b. the jacks to be used for multichannel. Because the jack color are based on MS's channel sequence, so the 'auto' model will pick the same jacks for multichannel MS uses. I did this to hope to minimize users questions. These code can also be applied to other codecs but I don't have any to test. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index a44d64e828..e64e29d 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -29,6 +29,7 @@ #include #include "hda_codec.h" #include "hda_local.h" +#define NUM_PINS 11 /* board config type */ @@ -38,6 +39,7 @@ enum { CMI_FULL, /* back 6-jack + front-panel 2-jack */ CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ + CMI_AUTO, /* let driver guess it */ }; struct cmi_spec { @@ -48,6 +50,7 @@ struct cmi_spec { /* playback */ struct hda_multi_out multiout; + hda_nid_t dac_nids[4]; /* NID for each DAC */ /* capture */ hda_nid_t *adc_nids; @@ -63,6 +66,15 @@ struct cmi_spec { const struct cmi_channel_mode *channel_modes; struct hda_pcm pcm_rec[2]; /* PCM information */ + + /* pin deafault configuration */ + hda_nid_t pin_nid[NUM_PINS]; + unsigned int def_conf[NUM_PINS]; + unsigned int pin_def_confs; + + /* multichannel pins */ + hda_nid_t multich_pin[4]; /* max 8-channel */ + struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ }; /* @@ -353,6 +365,175 @@ static int cmi9880_build_controls(struct hda_codec *codec) return 0; } +#define AC_DEFCFG_ASSOC_SHIFT 4 +#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) +#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) +#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) + +/* get all pin default configuration in def_conf */ +static int cmi9880_get_pin_def_config(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + hda_nid_t nid, nid_start; + int i = 0, nodes; + + nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); + for (nid = nid_start; nid < nodes + nid_start; nid++) { + unsigned int wid_caps = snd_hda_param_read(codec, nid, + AC_PAR_AUDIO_WIDGET_CAP); + unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + /* read all default configuration for pin complex */ + if (wid_type == AC_WID_PIN) { + spec->pin_nid[i] = nid; + spec->def_conf[i] = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + i++; + } + } + spec->pin_def_confs = i; + return 0; +} + +/* get a pin default configuration of nid in def_conf */ +static unsigned int cmi9880_get_def_config(struct hda_codec *codec, hda_nid_t nid) +{ + struct cmi_spec *spec = codec->spec; + int i = 0; + + while (spec->pin_nid[i] != nid && i < spec->pin_def_confs) + i++; + if (i == spec->pin_def_confs) + return (unsigned int) -1; + else + return spec->def_conf[i]; +} + +/* decide what pins to use for multichannel playback */ +static int cmi9880_get_multich_pins(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + int i, j, pins, seq[4]; + int max_channel = 0; + unsigned int def_conf, sequence; + hda_nid_t nid; + + memset(spec->multich_pin, 0, sizeof(spec->multich_pin)); + for (pins = 0, i = 0; i < spec->pin_def_confs && pins < 4; i++) { + def_conf = spec->def_conf[i]; + /* skip pin not connected */ + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) + continue; + /* get the sequence if association == 1 */ + /* the other pins have association = 0, incorrect in spec 1.0 */ + if (get_defcfg_association(def_conf) == 1) { + sequence = get_defcfg_sequence(def_conf); + seq[pins] = sequence; + spec->multich_pin[pins] = spec->pin_nid[i]; + pins++; // ready for next slot + max_channel += 2; + } + } + /* sort by sequence, data collected here will be for Windows */ + for (i = 0; i < pins; i++) { + for (j = i + 1; j < pins; j++) { + if (seq[j] < seq[i]) { + sequence = seq[j]; + nid = spec->multich_pin[j]; + seq[j] = seq[i]; + spec->multich_pin[j] = spec->multich_pin[i]; + seq[i] = sequence; + spec->multich_pin[i] = nid; + } + } + } + /* the pin assignment is for front, C/LFE, surround and back */ + if (max_channel >= 6) { + hda_nid_t temp; + /* exchange pin of C/LFE and surround */ + temp = spec->multich_pin[1]; + spec->multich_pin[1] = spec->multich_pin[2]; + spec->multich_pin[2] = temp; + } + return max_channel; +} + +/* fill in the multi_dac_nids table, which will decide + which audio widget to use for each channel */ +static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + hda_nid_t nid; + int assigned[4]; + int i, j; + + /* clear the table, only one c-media dac assumed here */ + memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); + memset(assigned, 0, sizeof(assigned)); + /* check the pins we found */ + for (i = 0; i < spec->multiout.max_channels / 2; i++) { + nid = spec->multich_pin[i]; + /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ + if (nid <= 0x0e && nid >= 0x0b) { + spec->dac_nids[i] = nid - 0x08; + assigned[nid - 0x0b] = 1; + } + } + /* left pin can be connect to any audio widget */ + for (i = 0; i < spec->multiout.max_channels / 2; i++) { + if (!assigned[i]) { + /* search for an empty channel */ + /* I should also check the pin type */ + for (j = 0; j < ARRAY_SIZE(spec->dac_nids); j++) + if (! spec->dac_nids[j]) { + spec->dac_nids[j] = i + 3; + assigned[i] = 1; + break; + } + } + } + return 0; +} + +/* create multi_init table, which is used for multichannel initialization */ +static int cmi9880_fill_multi_init(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + hda_nid_t nid; + int i, j, k, len; + + /* clear the table, only one c-media dac assumed here */ + memset(spec->multi_init, 0, sizeof(spec->multi_init)); + for (j = 0, i = 0; i < spec->multiout.max_channels / 2; i++) { + hda_nid_t conn[4]; + nid = spec->multich_pin[i]; + /* set as output */ + spec->multi_init[j].nid = nid; + spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; + spec->multi_init[j].param = 0xc0; + j++; + /* nid 0x0f,0x10,0x1f,0x20 are needed to set connection */ + switch (nid) { + case 0x0f: + case 0x10: + case 0x1f: + case 0x20: + /* set connection */ + spec->multi_init[j].nid = nid; + spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; + /* find the index in connect list */ + len = snd_hda_get_connections(codec, nid, conn, 4); + for (k = 0; k < len; k++) + if (conn[k] == spec->dac_nids[i]) + break; + spec->multi_init[j].param = k < len ? k : 0; + j++; + break; + } + } + return 0; +} + static int cmi9880_init(struct hda_codec *codec) { struct cmi_spec *spec = codec->spec; @@ -360,6 +541,8 @@ static int cmi9880_init(struct hda_codec *codec) snd_hda_sequence_write(codec, cmi9880_allout_init); else snd_hda_sequence_write(codec, cmi9880_basic_init); + if (spec->board_config == CMI_AUTO) + snd_hda_sequence_write(codec, spec->multi_init); return 0; } @@ -546,6 +729,7 @@ static struct hda_board_config cmi9880_cfg_tbl[] = { { .modelname = "full", .config = CMI_FULL }, { .modelname = "full_dig", .config = CMI_FULL_DIG }, { .modelname = "allout", .config = CMI_ALLOUT }, + { .modelname = "auto", .config = CMI_AUTO }, {} /* terminator */ }; @@ -570,10 +754,13 @@ static int patch_cmi9880(struct hda_codec *codec) codec->spec = spec; spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); if (spec->board_config < 0) { - snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); - spec->board_config = CMI_FULL_DIG; /* try everything */ + snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); + spec->board_config = CMI_AUTO; /* try everything */ } + /* copy default DAC NIDs */ + memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); + switch (spec->board_config) { case CMI_MINIMAL: case CMI_MIN_FP: @@ -605,10 +792,50 @@ static int patch_cmi9880(struct hda_codec *codec) spec->input_mux = &cmi9880_no_line_mux; spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; break; + case CMI_AUTO: + { + unsigned int port_e, port_f, port_g, port_h; + unsigned int port_spdifi, port_spdifo; + /* collect pin default configuration */ + cmi9880_get_pin_def_config(codec); + port_e = cmi9880_get_def_config(codec, 0x0f); + port_f = cmi9880_get_def_config(codec, 0x10); + port_g = cmi9880_get_def_config(codec, 0x1f); + port_h = cmi9880_get_def_config(codec, 0x20); + port_spdifi = cmi9880_get_def_config(codec, 0x13); + port_spdifo = cmi9880_get_def_config(codec, 0x12); + spec->front_panel = 1; + if ((get_defcfg_connect(port_e) == AC_JACK_PORT_NONE) + || (get_defcfg_connect(port_f) == AC_JACK_PORT_NONE)) { + spec->surr_switch = 1; + /* no front panel */ + if ((get_defcfg_connect(port_g) == AC_JACK_PORT_NONE) + || (get_defcfg_connect(port_h) == AC_JACK_PORT_NONE)) { + /* no optional rear panel */ + spec->board_config = CMI_MINIMAL; + spec->front_panel = 0; + spec->num_ch_modes = 2; + } else + spec->board_config = CMI_MIN_FP; + spec->num_ch_modes = 3; + spec->channel_modes = cmi9880_channel_modes; + spec->input_mux = &cmi9880_basic_mux; + } else { + spec->input_mux = &cmi9880_basic_mux; + if (get_defcfg_connect(port_spdifo) != 1) + spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; + if (get_defcfg_connect(port_spdifi) != 1) + spec->dig_in_nid = CMI_DIG_IN_NID; + } + spec->multiout.max_channels = cmi9880_get_multich_pins(codec); + cmi9880_fill_multi_dac_nids(codec); + cmi9880_fill_multi_init(codec); + } + break; } spec->multiout.num_dacs = 4; - spec->multiout.dac_nids = cmi9880_dac_nids; + spec->multiout.dac_nids = spec->dac_nids; spec->adc_nids = cmi9880_adc_nids; -- cgit v0.10.2 From df34140a9c15d4be8833f7977dca277a03ab87b0 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 9 Apr 2005 16:57:09 +0200 Subject: [ALSA] Display SPDIF in status in proc fs 'spdif-in' file. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 732d17d..187a4e6 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -44,28 +44,33 @@ static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu, unsigned int status, rate = 0; status = snd_emu10k1_ptr_read(emu, status_reg, 0); - if (rate_reg > 0) - rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); snd_iprintf(buffer, "\n%s\n", title); - snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no"); - snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no"); - snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no"); - snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]); - snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6); - snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8); - snd_iprintf(buffer, "Generation Status : %s\n", status & SPCS_GENERATIONSTATUS ? "original" : "copy"); - snd_iprintf(buffer, "Source Mask : %i\n", (status & SPCS_SOURCENUMMASK) >> 16); - snd_iprintf(buffer, "Channel Number : %s\n", channel[(status & SPCS_CHANNELNUMMASK) >> 20]); - snd_iprintf(buffer, "Sample Rate : %iHz\n", samplerate[(status & SPCS_SAMPLERATEMASK) >> 24]); - snd_iprintf(buffer, "Clock Accuracy : %s\n", clkaccy[(status & SPCS_CLKACCYMASK) >> 28]); - - if (rate_reg > 0) { - snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); - snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); - snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", rate & SRCS_ESTSAMPLERATE); + if (status != 0xffffffff) { + snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no"); + snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no"); + snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no"); + snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]); + snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6); + snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8); + snd_iprintf(buffer, "Generation Status : %s\n", status & SPCS_GENERATIONSTATUS ? "original" : "copy"); + snd_iprintf(buffer, "Source Mask : %i\n", (status & SPCS_SOURCENUMMASK) >> 16); + snd_iprintf(buffer, "Channel Number : %s\n", channel[(status & SPCS_CHANNELNUMMASK) >> 20]); + snd_iprintf(buffer, "Sample Rate : %iHz\n", samplerate[(status & SPCS_SAMPLERATEMASK) >> 24]); + snd_iprintf(buffer, "Clock Accuracy : %s\n", clkaccy[(status & SPCS_CLKACCYMASK) >> 28]); + + if (rate_reg > 0) { + rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); + snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); + snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); + /* From ((Rate * 48000 ) / 262144); */ + snd_iprintf(buffer, "Estimated Sample Rate : %d\n", ((rate & 0xFFFFF ) * 375) >> 11); + } + } else { + snd_iprintf(buffer, "No signal detected.\n"); } + } static void snd_emu10k1_proc_read(snd_info_entry_t *entry, @@ -223,15 +228,20 @@ static void snd_emu10k1_proc_read(snd_info_entry_t *entry, snd_iprintf(buffer, "\nAll FX Outputs :\n"); for (idx = 0; idx < (emu->audigy ? 64 : 32); idx++) snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]); - snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 0", SPCS0, -1); - snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 1", SPCS1, -1); - snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 2/3", SPCS2, -1); - snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF", CDCS, CDSRCS); - snd_emu10k1_proc_spdif_status(emu, buffer, "General purpose S/PDIF", GPSCS, GPSRCS); +} + +static void snd_emu10k1_proc_spdif_read(snd_info_entry_t *entry, + snd_info_buffer_t * buffer) +{ + emu10k1_t *emu = entry->private_data; + snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); + snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); +#if 0 val = snd_emu10k1_ptr_read(emu, ZVSRCS, 0); snd_iprintf(buffer, "\nZoomed Video\n"); snd_iprintf(buffer, "Rate Locked : %s\n", val & SRCS_RATELOCKED ? "on" : "off"); snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", val & SRCS_ESTSAMPLERATE); +#endif } static void snd_emu10k1_proc_acode_read(snd_info_entry_t *entry, @@ -526,6 +536,11 @@ int __devinit snd_emu10k1_proc_init(emu10k1_t * emu) if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read); + if (emu->card_capabilities->emu10k2_chip) { + if (! snd_card_proc_new(emu->card, "spdif-in", &entry)) + snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_spdif_read); + } + if (! snd_card_proc_new(emu->card, "voices", &entry)) snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read); -- cgit v0.10.2 From 001f758990d685e7023008763795f1970ef56614 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 9 Apr 2005 23:38:25 +0200 Subject: [ALSA] Improve SPDIF playback via the P16V/CA0151 chip. EMU10K1/EMU10K2 driver Although we can set 44100 as the output rate, the SPDIF can do it, but the Analog output cannot. The SPDIF has the bug, whereby the Left channel arrives one sample late, so although we don't do any resampling, it is not good for AC3 non-audio output. Signed-off-by: James Courtier-Dutton diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index f5babd3..61a3f418 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -747,6 +747,7 @@ /* Assumes sample lock */ /* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS. */ +#define SRCS_SPDIFVALID 0x04000000 /* SPDIF stream valid */ #define SRCS_SPDIFLOCKED 0x02000000 /* SPDIF stream locked */ #define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */ #define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */ diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index d0b2965..b544c25 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -935,10 +935,12 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; +#if 0 if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; +#endif } else if (! emu->card_capabilities->ecard) { /* sb live! */ if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 187a4e6..356fb71 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -30,6 +30,7 @@ #include #include #include +#include "p16v.h" static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu, snd_info_buffer_t * buffer, @@ -62,6 +63,7 @@ static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu, if (rate_reg > 0) { rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); + snd_iprintf(buffer, "S/PDIF Valid : %s\n", rate & SRCS_SPDIFVALID ? "on" : "off"); snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); /* From ((Rate * 48000 ) / 262144); */ @@ -244,6 +246,21 @@ static void snd_emu10k1_proc_spdif_read(snd_info_entry_t *entry, #endif } +static void snd_emu10k1_proc_rates_read(snd_info_entry_t *entry, + snd_info_buffer_t * buffer) +{ + static int samplerate[8] = { 44100, 48000, 96000, 192000, 4, 5, 6, 7 }; + emu10k1_t *emu = entry->private_data; + unsigned int val, tmp, n; + val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0); + tmp = (val >> 16) & 0x8; + for (n=0;n<4;n++) { + tmp = val >> (16 + (n*4)); + if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]); + else snd_iprintf(buffer, "Channel %d: No input\n", n); + } +} + static void snd_emu10k1_proc_acode_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { @@ -540,6 +557,10 @@ int __devinit snd_emu10k1_proc_init(emu10k1_t * emu) if (! snd_card_proc_new(emu->card, "spdif-in", &entry)) snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_spdif_read); } + if (emu->card_capabilities->ca0151_chip) { + if (! snd_card_proc_new(emu->card, "capture-rates", &entry)) + snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_rates_read); + } if (! snd_card_proc_new(emu->card, "voices", &entry)) snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read); diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index dd6ce99..8dd8783 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -119,8 +119,8 @@ static snd_pcm_hardware_t snd_p16v_playback_hw = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */ - .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 , - .rate_min = 48000, + .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, + .rate_min = 44100, .rate_max = 192000, .channels_min = 8, .channels_max = 8, @@ -324,19 +324,17 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); switch (runtime->rate) { case 44100: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x8000); /* FIXME: This will change the capture rate as well! */ - break; - case 48000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x0000); /* FIXME: This will change the capture rate as well! */ + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x8080); break; case 96000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x4000); /* FIXME: This will change the capture rate as well! */ + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x4040); break; case 192000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x2000); /* FIXME: This will change the capture rate as well! */ + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x2020); break; + case 48000: default: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, 0x0000); /* FIXME: This will change the capture rate as well! */ + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x0000); break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ -- cgit v0.10.2 From 310bacd29230abf5f2a230159e48e983171e0f26 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 10 Apr 2005 00:00:24 +0200 Subject: [ALSA] Improve playback startup. Increase buffer size, and reduce xruns. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 8dd8783..776761f 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -124,9 +124,9 @@ static snd_pcm_hardware_t snd_p16v_playback_hw = { .rate_max = 192000, .channels_min = 8, .channels_max = 8, - .buffer_bytes_max = (32*1024), + .buffer_bytes_max = ((65536 - 64) * 8), .period_bytes_min = 64, - .period_bytes_max = (16*1024), + .period_bytes_max = (65536 - 64), .periods_min = 2, .periods_max = 8, .fifo_size = 0, @@ -347,7 +347,8 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0); snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); - snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes + //snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes + snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0); snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0); snd_emu10k1_ptr20_write(emu, 0x08, channel, 0); @@ -602,7 +603,7 @@ int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), - 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */ + ((65536 - 64) * 8), ((65536 - 64) * 8))) < 0) return err; //snd_printk("preallocate playback substream: err=%d\n", err); } -- cgit v0.10.2 From fd9a98ec0a7c8ce15928e3454d73533146d9d57c Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 10 Apr 2005 15:43:35 +0200 Subject: [ALSA] Fix typo in speaker routing. Now sound comes from the correct speakers EMU10K1/EMU10K2 driver when using the p16v HD device. Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c6d53b4..bf17db1 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -189,7 +189,7 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir) /* Enabled Phased (8-channel) P16V playback */ outl(0x0201, emu->port + HCFG2); /* Set playback routing. */ - snd_emu10k1_ptr_write(emu, CAPTURE_P16V_SOURCE, 0, 78e4); + snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, 0x78e4); } if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ -- cgit v0.10.2 From aed058e8713f76be9258011238670064ea3e69a8 Mon Sep 17 00:00:00 2001 From: Simone Zinanni Date: Mon, 11 Apr 2005 14:08:40 +0200 Subject: [ALSA] Provides preliminary support for the Terratec Phase 28 card ICE1712 driver Provides preliminary support for the Terratec Phase 28 card. Not extensively tested and probably buggy, but it seems to work. Signed-off-by: Simone Zinanni Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 8bb1c58..5ad4728 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -373,6 +373,11 @@ struct _snd_ice1712 { unsigned short master[2]; unsigned short vol[8]; } aureon; + /* AC97 register cache for Phase28 */ + struct phase28_spec { + unsigned short master[2]; + unsigned short vol[8]; + } phase28; /* Hoontech-specific setting */ struct hoontech_spec { unsigned char boxbits[4]; diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index d1f9083..5bf734b 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -45,6 +45,47 @@ #include "envy24ht.h" #include "phase.h" +/* WM8770 registers */ +#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ +#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ +#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */ +#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */ +#define WM_PHASE_SWAP 0x12 /* DAC phase */ +#define WM_DAC_CTRL1 0x13 /* DAC control bits */ +#define WM_MUTE 0x14 /* mute controls */ +#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */ +#define WM_INT_CTRL 0x16 /* interface control */ +#define WM_MASTER 0x17 /* master clock and mode */ +#define WM_POWERDOWN 0x18 /* power-down controls */ +#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */ +#define WM_ADC_MUX 0x1b /* input MUX */ +#define WM_OUT_MUX1 0x1c /* output MUX */ +#define WM_OUT_MUX2 0x1e /* output MUX */ +#define WM_RESET 0x1f /* software reset */ + + +/* + * Logarithmic volume values for WM8770 + * Computed as 20 * Log10(255 / x) + */ +static unsigned char wm_vol[256] = { + 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, + 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, + 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, + 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 +}; + +#define WM_VOL_MAX (sizeof(wm_vol) - 1) +#define WM_VOL_MUTE 0x8000 + static akm4xxx_t akm_phase22 __devinitdata = { .type = SND_AK4524, .num_dacs = 2, @@ -124,6 +165,684 @@ static unsigned char phase22_eeprom[] __devinitdata = { 0x00, /* GPIO_STATE2 */ }; +static unsigned char phase28_eeprom[] __devinitdata = { + 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ + 0x80, /* ACLINK: I2S */ + 0xfc, /* I2S: vol, 96k, 24bit, 192k */ + 0xc3, /* SPDIF: out-en, out-int, spdif-in */ + 0xff, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0x5f, /* GPIO_DIR2 */ + 0x00, /* GPIO_MASK */ + 0x00, /* GPIO_MASK1 */ + 0x00, /* GPIO_MASK2 */ + 0x00, /* GPIO_STATE */ + 0x00, /* GPIO_STATE1 */ + 0x00, /* GPIO_STATE2 */ +}; + +/* + * write data in the SPI mode + */ +static void phase28_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits) +{ + unsigned int tmp; + int i; + + tmp = snd_ice1712_gpio_read(ice); + + snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|PHASE28_SPI_CLK| + PHASE28_WM_CS)); + tmp |= PHASE28_WM_RW; + tmp &= ~cs; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + + for (i = bits - 1; i >= 0; i--) { + tmp &= ~PHASE28_SPI_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + if (data & (1 << i)) + tmp |= PHASE28_SPI_MOSI; + else + tmp &= ~PHASE28_SPI_MOSI; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PHASE28_SPI_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + } + + tmp &= ~PHASE28_SPI_CLK; + tmp |= cs; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PHASE28_SPI_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); +} + +/* + * get the current register value of WM codec + */ +static unsigned short wm_get(ice1712_t *ice, int reg) +{ + reg <<= 1; + return ((unsigned short)ice->akm[0].images[reg] << 8) | + ice->akm[0].images[reg + 1]; +} + +/* + * set the register value of WM codec + */ +static void wm_put_nocache(ice1712_t *ice, int reg, unsigned short val) +{ + phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16); +} + +/* + * set the register value of WM codec and remember it + */ +static void wm_put(ice1712_t *ice, int reg, unsigned short val) +{ + wm_put_nocache(ice, reg, val); + reg <<= 1; + ice->akm[0].images[reg] = val >> 8; + ice->akm[0].images[reg + 1] = val; +} + +static void wm_set_vol(ice1712_t *ice, unsigned int index, unsigned short vol, unsigned short master) +{ + unsigned char nvol; + + if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) + nvol = 0; + else + nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX]; + + wm_put(ice, index, nvol); + wm_put_nocache(ice, index, 0x180 | nvol); +} + +/* + * DAC mute control + */ +#define wm_pcm_mute_info phase28_mono_bool_info + +static int wm_pcm_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + down(&ice->gpio_mutex); + ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_pcm_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short nval, oval; + int change; + + snd_ice1712_save_gpio_status(ice); + oval = wm_get(ice, WM_MUTE); + nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10); + if ((change = (nval != oval))) + wm_put(ice, WM_MUTE, nval); + snd_ice1712_restore_gpio_status(ice); + + return change; +} + +/* + * Master volume attenuation mixer control + */ +static int wm_master_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = WM_VOL_MAX; + return 0; +} + +static int wm_master_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int i; + for (i=0; i<2; i++) + ucontrol->value.integer.value[i] = ice->spec.phase28.master[i] & ~WM_VOL_MUTE; + return 0; +} + +static int wm_master_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int ch, change = 0; + + snd_ice1712_save_gpio_status(ice); + for (ch = 0; ch < 2; ch++) { + if (ucontrol->value.integer.value[ch] != ice->spec.phase28.master[ch]) { + int dac; + ice->spec.phase28.master[ch] &= WM_VOL_MUTE; + ice->spec.phase28.master[ch] |= ucontrol->value.integer.value[ch]; + for (dac = 0; dac < ice->num_total_dacs; dac += 2) + wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, + ice->spec.phase28.vol[dac + ch], + ice->spec.phase28.master[ch]); + change = 1; + } + } + snd_ice1712_restore_gpio_status(ice); + return change; +} + +static int __devinit phase28_init(ice1712_t *ice) +{ + static unsigned short wm_inits_phase28[] = { + /* These come first to reduce init pop noise */ + 0x1b, 0x044, /* ADC Mux (AC'97 source) */ + 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ + 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */ + + 0x18, 0x000, /* All power-up */ + + 0x16, 0x122, /* I2S, normal polarity, 24bit */ + 0x17, 0x022, /* 256fs, slave mode */ + 0x00, 0, /* DAC1 analog mute */ + 0x01, 0, /* DAC2 analog mute */ + 0x02, 0, /* DAC3 analog mute */ + 0x03, 0, /* DAC4 analog mute */ + 0x04, 0, /* DAC5 analog mute */ + 0x05, 0, /* DAC6 analog mute */ + 0x06, 0, /* DAC7 analog mute */ + 0x07, 0, /* DAC8 analog mute */ + 0x08, 0x100, /* master analog mute */ + 0x09, 0xff, /* DAC1 digital full */ + 0x0a, 0xff, /* DAC2 digital full */ + 0x0b, 0xff, /* DAC3 digital full */ + 0x0c, 0xff, /* DAC4 digital full */ + 0x0d, 0xff, /* DAC5 digital full */ + 0x0e, 0xff, /* DAC6 digital full */ + 0x0f, 0xff, /* DAC7 digital full */ + 0x10, 0xff, /* DAC8 digital full */ + 0x11, 0x1ff, /* master digital full */ + 0x12, 0x000, /* phase normal */ + 0x13, 0x090, /* unmute DAC L/R */ + 0x14, 0x000, /* all unmute */ + 0x15, 0x000, /* no deemphasis, no ZFLG */ + 0x19, 0x000, /* -12dB ADC/L */ + 0x1a, 0x000, /* -12dB ADC/R */ + (unsigned short)-1 + }; + + unsigned int tmp; + akm4xxx_t *ak; + unsigned short *p; + int i; + + ice->num_total_dacs = 8; + ice->num_total_adcs = 2; + + // Initialize analog chips + ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); + if (!ak) + return -ENOMEM; + ice->akm_codecs = 1; + + snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */ + + /* reset the wm codec as the SPI mode */ + snd_ice1712_save_gpio_status(ice); + snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|PHASE28_HP_SEL)); + + tmp = snd_ice1712_gpio_read(ice); + tmp &= ~PHASE28_WM_RESET; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PHASE28_WM_CS; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PHASE28_WM_RESET; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + + p = wm_inits_phase28; + for (; *p != (unsigned short)-1; p += 2) + wm_put(ice, p[0], p[1]); + + snd_ice1712_restore_gpio_status(ice); + + ice->spec.phase28.master[0] = WM_VOL_MUTE; + ice->spec.phase28.master[1] = WM_VOL_MUTE; + for (i = 0; i < ice->num_total_dacs; i++) { + ice->spec.phase28.vol[i] = WM_VOL_MUTE; + wm_set_vol(ice, i, ice->spec.phase28.vol[i], ice->spec.phase28.master[i % 2]); + } + + return 0; +} + +/* + * DAC volume attenuation mixer control + */ +static int wm_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + int voices = kcontrol->private_value >> 8; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = voices; + uinfo->value.integer.min = 0; /* mute (-101dB) */ + uinfo->value.integer.max = 0x7F; /* 0dB */ + return 0; +} + +static int wm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int i, ofs, voices; + + voices = kcontrol->private_value >> 8; + ofs = kcontrol->private_value & 0xff; + for (i = 0; i < voices; i++) + ucontrol->value.integer.value[i] = ice->spec.phase28.vol[ofs+i] & ~WM_VOL_MUTE; + return 0; +} + +static int wm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int i, idx, ofs, voices; + int change = 0; + + voices = kcontrol->private_value >> 8; + ofs = kcontrol->private_value & 0xff; + snd_ice1712_save_gpio_status(ice); + for (i = 0; i < voices; i++) { + idx = WM_DAC_ATTEN + ofs + i; + if (ucontrol->value.integer.value[i] != ice->spec.phase28.vol[ofs+i]) { + ice->spec.phase28.vol[ofs+i] &= WM_VOL_MUTE; + ice->spec.phase28.vol[ofs+i] |= ucontrol->value.integer.value[i]; + wm_set_vol(ice, idx, ice->spec.phase28.vol[ofs+i], + ice->spec.phase28.master[i]); + change = 1; + } + } + snd_ice1712_restore_gpio_status(ice); + return change; +} + +/* + * WM8770 mute control + */ +static int wm_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = kcontrol->private_value >> 8; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int wm_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int voices, ofs, i; + + voices = kcontrol->private_value >> 8; + ofs = kcontrol->private_value & 0xFF; + + for (i = 0; i < voices; i++) + ucontrol->value.integer.value[i] = (ice->spec.phase28.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1; + return 0; +} + +static int wm_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int change = 0, voices, ofs, i; + + voices = kcontrol->private_value >> 8; + ofs = kcontrol->private_value & 0xFF; + + snd_ice1712_save_gpio_status(ice); + for (i = 0; i < voices; i++) { + int val = (ice->spec.phase28.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; + if (ucontrol->value.integer.value[i] != val) { + ice->spec.phase28.vol[ofs + i] &= ~WM_VOL_MUTE; + ice->spec.phase28.vol[ofs + i] |= + ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; + wm_set_vol(ice, ofs + i, ice->spec.phase28.vol[ofs + i], + ice->spec.phase28.master[i]); + change = 1; + } + } + snd_ice1712_restore_gpio_status(ice); + + return change; +} + +/* + * WM8770 master mute control + */ +static int wm_master_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int wm_master_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = (ice->spec.phase28.master[0] & WM_VOL_MUTE) ? 0 : 1; + ucontrol->value.integer.value[1] = (ice->spec.phase28.master[1] & WM_VOL_MUTE) ? 0 : 1; + return 0; +} + +static int wm_master_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int change = 0, i; + + snd_ice1712_save_gpio_status(ice); + for (i = 0; i < 2; i++) { + int val = (ice->spec.phase28.master[i] & WM_VOL_MUTE) ? 0 : 1; + if (ucontrol->value.integer.value[i] != val) { + int dac; + ice->spec.phase28.master[i] &= ~WM_VOL_MUTE; + ice->spec.phase28.master[i] |= + ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; + for (dac = 0; dac < ice->num_total_dacs; dac += 2) + wm_set_vol(ice, WM_DAC_ATTEN + dac + i, + ice->spec.phase28.vol[dac + i], + ice->spec.phase28.master[i]); + change = 1; + } + } + snd_ice1712_restore_gpio_status(ice); + + return change; +} + +/* digital master volume */ +#define PCM_0dB 0xff +#define PCM_RES 128 /* -64dB */ +#define PCM_MIN (PCM_0dB - PCM_RES) +static int wm_pcm_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* mute (-64dB) */ + uinfo->value.integer.max = PCM_RES; /* 0dB */ + return 0; +} + +static int wm_pcm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short val; + + down(&ice->gpio_mutex); + val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; + val = val > PCM_MIN ? (val - PCM_MIN) : 0; + ucontrol->value.integer.value[0] = val; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_pcm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short ovol, nvol; + int change = 0; + + snd_ice1712_save_gpio_status(ice); + nvol = ucontrol->value.integer.value[0]; + nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; + ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; + if (ovol != nvol) { + wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */ + wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */ + change = 1; + } + snd_ice1712_restore_gpio_status(ice); + return change; +} + +/* + */ +static int phase28_mono_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +/* + * Deemphasis + */ +#define phase28_deemp_info phase28_mono_bool_info + +static int phase28_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf; + return 0; +} + +static int phase28_deemp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int temp, temp2; + temp2 = temp = wm_get(ice, WM_DAC_CTRL2); + if (ucontrol->value.integer.value[0]) + temp |= 0xf; + else + temp &= ~0xf; + if (temp != temp2) { + wm_put(ice, WM_DAC_CTRL2, temp); + return 1; + } + return 0; +} + +/* + * ADC Oversampling + */ +static int phase28_oversampling_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { "128x", "64x" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int phase28_oversampling_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8; + return 0; +} + +static int phase28_oversampling_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + int temp, temp2; + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + temp2 = temp = wm_get(ice, WM_MASTER); + + if (ucontrol->value.enumerated.item[0]) + temp |= 0x8; + else + temp &= ~0x8; + + if (temp != temp2) { + wm_put(ice, WM_MASTER, temp); + return 1; + } + return 0; +} + +static snd_kcontrol_new_t phase28_dac_controls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = wm_master_mute_info, + .get = wm_master_mute_get, + .put = wm_master_mute_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = wm_master_vol_info, + .get = wm_master_vol_get, + .put = wm_master_vol_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Front Playback Switch", + .info = wm_mute_info, + .get = wm_mute_get, + .put = wm_mute_put, + .private_value = (2 << 8) | 0 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Front Playback Volume", + .info = wm_vol_info, + .get = wm_vol_get, + .put = wm_vol_put, + .private_value = (2 << 8) | 0 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Rear Playback Switch", + .info = wm_mute_info, + .get = wm_mute_get, + .put = wm_mute_put, + .private_value = (2 << 8) | 2 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Rear Playback Volume", + .info = wm_vol_info, + .get = wm_vol_get, + .put = wm_vol_put, + .private_value = (2 << 8) | 2 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Center Playback Switch", + .info = wm_mute_info, + .get = wm_mute_get, + .put = wm_mute_put, + .private_value = (1 << 8) | 4 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Center Playback Volume", + .info = wm_vol_info, + .get = wm_vol_get, + .put = wm_vol_put, + .private_value = (1 << 8) | 4 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "LFE Playback Switch", + .info = wm_mute_info, + .get = wm_mute_get, + .put = wm_mute_put, + .private_value = (1 << 8) | 5 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "LFE Playback Volume", + .info = wm_vol_info, + .get = wm_vol_get, + .put = wm_vol_put, + .private_value = (1 << 8) | 5 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Side Playback Switch", + .info = wm_mute_info, + .get = wm_mute_get, + .put = wm_mute_put, + .private_value = (2 << 8) | 6 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Side Playback Volume", + .info = wm_vol_info, + .get = wm_vol_get, + .put = wm_vol_put, + .private_value = (2 << 8) | 6 + } +}; + +static snd_kcontrol_new_t wm_controls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Switch", + .info = wm_pcm_mute_info, + .get = wm_pcm_mute_get, + .put = wm_pcm_mute_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .info = wm_pcm_vol_info, + .get = wm_pcm_vol_get, + .put = wm_pcm_vol_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Deemphasis Switch", + .info = phase28_deemp_info, + .get = phase28_deemp_get, + .put = phase28_deemp_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC Oversampling", + .info = phase28_oversampling_info, + .get = phase28_oversampling_get, + .put = phase28_oversampling_put + } +}; + +static int __devinit phase28_add_controls(ice1712_t *ice) +{ + unsigned int i, counts; + int err; + + counts = ARRAY_SIZE(phase28_dac_controls); + for (i = 0; i < counts; i++) { + err = snd_ctl_add(ice->card, snd_ctl_new1(&phase28_dac_controls[i], ice)); + if (err < 0) + return err; + } + + for (i = 0; i < ARRAY_SIZE(wm_controls); i++) { + err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice)); + if (err < 0) + return err; + } + + return 0; +} + struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { { .subvendor = VT1724_SUBDEVICE_PHASE22, @@ -134,5 +853,14 @@ struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { .eeprom_size = sizeof(phase22_eeprom), .eeprom_data = phase22_eeprom, }, + { + .subvendor = VT1724_SUBDEVICE_PHASE28, + .name = "Terratec PHASE 28", + .model = "phase28", + .chip_init = phase28_init, + .build_controls = phase28_add_controls, + .eeprom_size = sizeof(phase28_eeprom), + .eeprom_data = phase28_eeprom, + }, { } /* terminator */ }; diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h index 6230cf1..13e841b 100644 --- a/sound/pci/ice1712/phase.h +++ b/sound/pci/ice1712/phase.h @@ -24,11 +24,28 @@ * */ -#define PHASE_DEVICE_DESC "{Terratec,Phase 22}," +#define PHASE_DEVICE_DESC "{Terratec,Phase 22},"\ + "{Terratec,Phase 28}," #define VT1724_SUBDEVICE_PHASE22 0x3b155011 +#define VT1724_SUBDEVICE_PHASE28 0x3b154911 /* entry point */ extern struct snd_ice1712_card_info snd_vt1724_phase_cards[]; +/* PHASE28 GPIO bits */ +#define PHASE28_SPI_MISO (1 << 21) +#define PHASE28_WM_RESET (1 << 20) +#define PHASE28_SPI_CLK (1 << 19) +#define PHASE28_SPI_MOSI (1 << 18) +#define PHASE28_WM_RW (1 << 17) +#define PHASE28_AC97_RESET (1 << 16) +#define PHASE28_DIGITAL_SEL1 (1 << 15) +#define PHASE28_HP_SEL (1 << 14) +#define PHASE28_WM_CS (1 << 12) +#define PHASE28_AC97_COMMIT (1 << 11) +#define PHASE28_AC97_ADDR (1 << 10) +#define PHASE28_AC97_DATA_LOW (1 << 9) +#define PHASE28_AC97_DATA_HIGH (1 << 8) +#define PHASE28_AC97_DATA_MASK 0xFF #endif /* __SOUND_PHASE */ -- cgit v0.10.2 From 467a8c2f41ab4b96a7c604619eb7465db403dda8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 11 Apr 2005 14:11:00 +0200 Subject: [ALSA] remove dead code YMFPCI driver This patch removes some dead code found by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 05f1629..997cf37 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -1421,17 +1421,15 @@ static snd_kcontrol_new_t snd_ymfpci_drec_source __devinitdata = { static int snd_ymfpci_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - unsigned int mask = 1; - switch (kcontrol->private_value) { case YDSXGR_SPDIFOUTCTRL: break; case YDSXGR_SPDIFINCTRL: break; default: return -EINVAL; } - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; + uinfo->value.integer.max = 1; return 0; } @@ -1439,7 +1437,7 @@ static int snd_ymfpci_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t { ymfpci_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value; - unsigned int shift = 0, mask = 1, invert = 0; + unsigned int shift = 0, mask = 1; switch (kcontrol->private_value) { case YDSXGR_SPDIFOUTCTRL: break; @@ -1447,8 +1445,6 @@ static int snd_ymfpci_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t default: return -EINVAL; } ucontrol->value.integer.value[0] = (snd_ymfpci_readl(chip, reg) >> shift) & mask; - if (invert) - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0; } @@ -1456,7 +1452,7 @@ static int snd_ymfpci_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t { ymfpci_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value; - unsigned int shift = 0, mask = 1, invert = 0; + unsigned int shift = 0, mask = 1; int change; unsigned int val, oval; @@ -1466,8 +1462,6 @@ static int snd_ymfpci_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t default: return -EINVAL; } val = (ucontrol->value.integer.value[0] & mask); - if (invert) - val = mask - val; val <<= shift; spin_lock_irq(&chip->reg_lock); oval = snd_ymfpci_readl(chip, reg); @@ -1487,14 +1481,13 @@ static int snd_ymfpci_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t static int snd_ymfpci_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { unsigned int reg = kcontrol->private_value; - unsigned int mask = 16383; if (reg < 0x80 || reg >= 0xc0) return -EINVAL; - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; + uinfo->value.integer.max = 16383; return 0; } @@ -1502,7 +1495,7 @@ static int snd_ymfpci_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t { ymfpci_t *chip = snd_kcontrol_chip(kcontrol); unsigned int reg = kcontrol->private_value; - unsigned int shift_left = 0, shift_right = 16, mask = 16383, invert = 0; + unsigned int shift_left = 0, shift_right = 16, mask = 16383; unsigned int val; if (reg < 0x80 || reg >= 0xc0) @@ -1512,10 +1505,6 @@ static int snd_ymfpci_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t spin_unlock_irq(&chip->reg_lock); ucontrol->value.integer.value[0] = (val >> shift_left) & mask; ucontrol->value.integer.value[1] = (val >> shift_right) & mask; - if (invert) { - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; - } return 0; } @@ -1523,7 +1512,7 @@ static int snd_ymfpci_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t { ymfpci_t *chip = snd_kcontrol_chip(kcontrol); unsigned int reg = kcontrol->private_value; - unsigned int shift_left = 0, shift_right = 16, mask = 16383, invert = 0; + unsigned int shift_left = 0, shift_right = 16, mask = 16383; int change; unsigned int val1, val2, oval; @@ -1531,10 +1520,6 @@ static int snd_ymfpci_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t return -EINVAL; val1 = ucontrol->value.integer.value[0] & mask; val2 = ucontrol->value.integer.value[1] & mask; - if (invert) { - val1 = mask - val1; - val2 = mask - val2; - } val1 <<= shift_left; val2 <<= shift_right; spin_lock_irq(&chip->reg_lock); -- cgit v0.10.2 From 26be865923ce9edefe8ddc007ddb1c098c29c449 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Mon, 11 Apr 2005 14:17:19 +0200 Subject: [ALSA] Add PCI ID for Gallant Odyssey Sound 4 FM801 driver The Gallant Odyssey Sound 4 card is based on the ForteMedia FM801 chip, but has a different PCI ID. Signed-off-by: Sergey Vlasov Signed-off-by: Takashi Iwai diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 08e7c5a..3291434 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -195,6 +195,7 @@ struct _snd_fm801 { static struct pci_device_id snd_fm801_ids[] = { { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ + { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ { 0, } }; -- cgit v0.10.2 From 2d7eb7cb2bab1fbe8cfb610277b19ad40a9f7c75 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Mon, 11 Apr 2005 15:04:33 +0200 Subject: [ALSA] Support all sample rate conversion capabilities of DXS channels Documentation,VIA82xx driver Add support for full sample rate conversion capabilities of DXS channels present in VIA VT8233/5/7 controllers: - any sample rate in the 8000 ... 48000 Hz range is supported even if the AC'97 codec supports only 48000 Hz output; - different DXS channels can use different sample rates at the same time (the controller performs required sample rate conversion and mixing in hardware). Signed-off-by: Sergey Vlasov Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 71ef049..c69581c 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1211,16 +1211,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ------------------ Module for AC'97 motherboards based on VIA 82C686A/686B, 8233, - 8233A, 8233C, 8235 (south) bridge. + 8233A, 8233C, 8235, 8237 (south) bridge. mpu_port - 0x300,0x310,0x320,0x330, otherwise obtain BIOS setup [VIA686A/686B only] joystick - Enable joystick (default off) [VIA686A/686B only] ac97_clock - AC'97 codec clock base (default 48000Hz) dxs_support - support DXS channels, - 0 = auto (defalut), 1 = enable, 2 = disable, - 3 = 48k only, 4 = no VRA - [VIA8233/C,8235 only] + 0 = auto (default), 1 = enable, 2 = disable, + 3 = 48k only, 4 = no VRA, 5 = enable any sample + rate and different sample rates on different + channels + [VIA8233/C, 8235, 8237 only] ac97_quirk - AC'97 workaround for strange hardware See the description of intel8x0 module for details. @@ -1232,18 +1234,21 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. default value 1.4. Then the interrupt number will be assigned under 15. You might also upgrade your BIOS. - Note: VIA8233/5 (not VIA8233A) can support DXS (direct sound) + Note: VIA8233/5/7 (not VIA8233A) can support DXS (direct sound) channels as the first PCM. On these channels, up to 4 - streams can be played at the same time. + streams can be played at the same time, and the controller + can perform sample rate conversion with separate rates for + each channel. As default (dxs_support = 0), 48k fixed rate is chosen except for the known devices since the output is often noisy except for 48k on some mother boards due to the bug of BIOS. - Please try once dxs_support=1 and if it works on other + Please try once dxs_support=5 and if it works on other sample rates (e.g. 44.1kHz of mp3 playback), please let us know the PCI subsystem vendor/device id's (output of "lspci -nv"). - If it doesn't work, try dxs_support=4. If it still doesn't + If dxs_support=5 does not work, try dxs_support=1; if it + doesn't work too, try dxs_support=4. If it still doesn't work and the default setting is ok, dxs_support=3 is the right choice. If the default setting doesn't work at all, try dxs_support=2 to disable the DXS channels. diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 9b4d74d..2f1e6eb 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -101,7 +101,7 @@ MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); module_param_array(ac97_quirk, charp, NULL, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); module_param_array(dxs_support, int, NULL, 0444); -MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)"); +MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)"); /* pci ids */ @@ -302,6 +302,7 @@ DEFINE_VIA_REGSET(CAPTURE_8233, 0x60); #define VIA_DXS_DISABLE 2 #define VIA_DXS_48K 3 #define VIA_DXS_NO_VRA 4 +#define VIA_DXS_SRC 5 /* @@ -380,6 +381,7 @@ struct _snd_via82xx { struct via_rate_lock rates[2]; /* playback and capture */ unsigned int dxs_fixed: 1; /* DXS channel accepts only 48kHz */ unsigned int no_vra: 1; /* no need to set VRA on DXS channels */ + unsigned int dxs_src: 1; /* use full SRC capabilities of DXS */ unsigned int spdif_on: 1; /* only spdif rates work to external DACs */ snd_pcm_t *pcms[2]; @@ -924,15 +926,16 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream) via82xx_t *chip = snd_pcm_substream_chip(substream); viadev_t *viadev = (viadev_t *)substream->runtime->private_data; snd_pcm_runtime_t *runtime = substream->runtime; + int ac97_rate = chip->dxs_src ? 48000 : runtime->rate; int rate_changed; u32 rbits; - if ((rate_changed = via_lock_rate(&chip->rates[0], runtime->rate)) < 0) + if ((rate_changed = via_lock_rate(&chip->rates[0], ac97_rate)) < 0) return rate_changed; if (rate_changed) { snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, chip->no_vra ? 48000 : runtime->rate); - snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); + snd_ac97_set_rate(chip->ac97, AC97_SPDIF, ac97_rate); } if (runtime->rate == 48000) rbits = 0xfffff; @@ -1074,6 +1077,12 @@ static int snd_via82xx_pcm_open(via82xx_t *chip, viadev_t *viadev, snd_pcm_subst /* fixed DXS playback rate */ runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; + } else if (chip->dxs_src && viadev->reg_offset < 0x40) { + /* use full SRC capabilities of DXS */ + runtime->hw.rates = (SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_8000_48000); + runtime->hw.rate_min = 8000; + runtime->hw.rate_max = 48000; } else if (! ratep->rate) { int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; runtime->hw.rates = chip->ac97->rates[idx]; @@ -2149,6 +2158,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ { .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ + { .vendor = 0x1043, .device = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ @@ -2288,6 +2298,10 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, chip->dxs_fixed = 1; else if (dxs_support[dev] == VIA_DXS_NO_VRA) chip->no_vra = 1; + else if (dxs_support[dev] == VIA_DXS_SRC) { + chip->no_vra = 1; + chip->dxs_src = 1; + } } if ((err = snd_via8233_init_misc(chip, dev)) < 0) goto __error; -- cgit v0.10.2 From 01ef355f0c34d6fbb451512e70e4cf336776b7fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Apr 2005 15:08:32 +0200 Subject: [ALSA] Fix SPDIF rate with dxs_support=4 VIA82xx driver Fix SPDIF rate setting with dxs_support=4. It should be 48k fixed. Signed-off-by: Takashi Iwai diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 2f1e6eb..e6e746f 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -935,7 +935,8 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream) if (rate_changed) { snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, chip->no_vra ? 48000 : runtime->rate); - snd_ac97_set_rate(chip->ac97, AC97_SPDIF, ac97_rate); + snd_ac97_set_rate(chip->ac97, AC97_SPDIF, + chip->no_vra ? 48000 : runtime->rate); } if (runtime->rate == 48000) rbits = 0xfffff; -- cgit v0.10.2 From 01d25d460a3b28aab537fab9a0038d1b5832ce28 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Apr 2005 16:58:24 +0200 Subject: [ALSA] Replace pci_module_init() with pci_register_driver() Documentation,ALS4000 driver,ATIIXP driver,ATIIXP-modem driver AZT3328 driver,BT87x driver,CMIPCI driver,CS4281 driver ENS1370/1+ driver,ES1938 driver,ES1968 driver,FM801 driver Intel8x0 driver,Intel8x0-modem driver,Maestro3 driver,RME32 driver RME96 driver,SonicVibes driver,VIA82xx driver,VIA82xx-modem driver ALI5451 driver,au88x0 driver,CA0106 driver,CS46xx driver EMU10K1/EMU10K2 driver,HDA Intel driver,ICE1712 driver,ICE1724 driver KORG1212 driver,MIXART driver,NM256 driver,RME HDSP driver RME9652 driver,Trident driver,Digigram VX222 driver,YMFPCI driver Replace the obsolete pci_module_init() with pci_register_driver(). Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index e789475..db0b7d2 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -371,7 +371,7 @@ create probe() callback. create remove() callback. create pci_driver table which contains the three pointers above. - create init() function just calling pci_module_init() to register the pci_driver table defined above. + create init() function just calling pci_register_driver() to register the pci_driver table defined above. create exit() function to call pci_unregister_driver() function. @@ -1198,7 +1198,7 @@ /* initialization of the module */ static int __init alsa_card_mychip_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } /* clean up the module */ @@ -1654,7 +1654,7 @@ 0) + if ((err = pci_register_driver(&driver)) > 0) return err; return 0; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 113208f..b450338 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -519,40 +519,50 @@ inline static unsigned char snd_cmipci_read_b(cmipci_t *cm, unsigned int cmd) } /* bit operations for dword register */ -static void snd_cmipci_set_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) +static int snd_cmipci_set_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) { - unsigned int val; - val = inl(cm->iobase + cmd); + unsigned int val, oval; + val = oval = inl(cm->iobase + cmd); val |= flag; + if (val == oval) + return 0; outl(val, cm->iobase + cmd); + return 1; } -static void snd_cmipci_clear_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) +static int snd_cmipci_clear_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) { - unsigned int val; - val = inl(cm->iobase + cmd); + unsigned int val, oval; + val = oval = inl(cm->iobase + cmd); val &= ~flag; + if (val == oval) + return 0; outl(val, cm->iobase + cmd); + return 1; } -#if 0 // not used /* bit operations for byte register */ -static void snd_cmipci_set_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) +static int snd_cmipci_set_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) { - unsigned char val; - val = inb(cm->iobase + cmd); + unsigned char val, oval; + val = oval = inb(cm->iobase + cmd); val |= flag; + if (val == oval) + return 0; outb(val, cm->iobase + cmd); + return 1; } -static void snd_cmipci_clear_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) +static int snd_cmipci_clear_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) { - unsigned char val; - val = inb(cm->iobase + cmd); + unsigned char val, oval; + val = oval = inb(cm->iobase + cmd); val &= ~flag; + if (val == oval) + return 0; outb(val, cm->iobase + cmd); + return 1; } -#endif /* @@ -2250,8 +2260,8 @@ DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, 0, 0, 0); /* rever DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, CM_XCHGDAC, 0, 0); #endif DEFINE_BIT_SWITCH_ARG(fourch, CM_REG_MISC_CTRL, CM_N4SPK3D, 0, 0); -DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0); -DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0); +// DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0); +// DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0); // DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); /* now module option */ DEFINE_SWITCH_ARG(modem, CM_REG_MISC_CTRL, CM_FLINKON|CM_FLINKOFF, CM_FLINKON, 0, 0); @@ -2300,10 +2310,114 @@ static int snd_cmipci_spdout_enable_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_v } +static int snd_cmipci_line_in_mode_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + cmipci_t *cm = snd_kcontrol_chip(kcontrol); + static char *texts[3] = { "Line-In", "Rear Output", "Bass Output" }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = cm->chip_version >= 39 ? 3 : 2; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static inline unsigned int get_line_in_mode(cmipci_t *cm) +{ + unsigned int val; + if (cm->chip_version >= 39) { + val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL); + if (val & CM_LINE_AS_BASS) + return 2; + } + val = snd_cmipci_read_b(cm, CM_REG_MIXER1); + if (val & CM_SPK4) + return 1; + return 0; +} + +static int snd_cmipci_line_in_mode_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cmipci_t *cm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&cm->reg_lock); + ucontrol->value.enumerated.item[0] = get_line_in_mode(cm); + spin_unlock_irq(&cm->reg_lock); + return 0; +} + +static int snd_cmipci_line_in_mode_put(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cmipci_t *cm = snd_kcontrol_chip(kcontrol); + int change; + + spin_lock_irq(&cm->reg_lock); + if (ucontrol->value.enumerated.item[0] == 2) + change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS); + else + change = snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS); + if (ucontrol->value.enumerated.item[0] == 1) + change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_SPK4); + else + change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_SPK4); + spin_unlock_irq(&cm->reg_lock); + return change; +} + +static int snd_cmipci_mic_in_mode_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { "Mic-In", "Center/LFE Output" }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_cmipci_mic_in_mode_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cmipci_t *cm = snd_kcontrol_chip(kcontrol); + /* same bit as spdi_phase */ + spin_lock_irq(&cm->reg_lock); + ucontrol->value.enumerated.item[0] = + (snd_cmipci_read_b(cm, CM_REG_MISC) & CM_SPDIF_INVERSE) ? 1 : 0; + spin_unlock_irq(&cm->reg_lock); + return 0; +} + +static int snd_cmipci_mic_in_mode_put(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cmipci_t *cm = snd_kcontrol_chip(kcontrol); + int change; + + spin_lock_irq(&cm->reg_lock); + if (ucontrol->value.enumerated.item[0]) + change = snd_cmipci_set_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE); + else + change = snd_cmipci_clear_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE); + spin_unlock_irq(&cm->reg_lock); + return change; +} + /* both for CM8338/8738 */ static snd_kcontrol_new_t snd_cmipci_mixer_switches[] __devinitdata = { DEFINE_MIXER_SWITCH("Four Channel Mode", fourch), - DEFINE_MIXER_SWITCH("Line-In As Rear", line_rear), + { + .name = "Line-In Mode", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = snd_cmipci_line_in_mode_info, + .get = snd_cmipci_line_in_mode_get, + .put = snd_cmipci_line_in_mode_put, + }, }; /* for non-multichannel chips */ @@ -2341,10 +2455,15 @@ static snd_kcontrol_new_t snd_cmipci_old_mixer_switches[] __devinitdata = { /* only for model 039 or later */ static snd_kcontrol_new_t snd_cmipci_extra_mixer_switches[] __devinitdata = { - DEFINE_MIXER_SWITCH("Line-In As Bass", line_bass), DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_sel2), DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase2), - DEFINE_MIXER_SWITCH("Mic As Center/LFE", spdi_phase), /* same bit as spdi_phase */ + { + .name = "Mic-In Mode", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = snd_cmipci_mic_in_mode_info, + .get = snd_cmipci_mic_in_mode_get, + .put = snd_cmipci_mic_in_mode_put, + } }; /* card control switches */ @@ -2944,7 +3063,7 @@ static struct pci_driver driver = { static int __init alsa_card_cmipci_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_cmipci_exit(void) diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index d7e06b3..8b42e86 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -2124,7 +2124,7 @@ static struct pci_driver driver = { static int __init alsa_card_cs4281_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_cs4281_exit(void) diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 25d6466..db212ec 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -171,7 +171,7 @@ static struct pci_driver driver = { static int __init alsa_card_cs46xx_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_cs46xx_exit(void) diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 6446afe..2085a99 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -228,7 +228,7 @@ static struct pci_driver driver = { static int __init alsa_card_emu10k1_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_emu10k1_exit(void) diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 27dfd8d..04ba637 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1627,7 +1627,7 @@ static int __init alsa_card_emu10k1x_init(void) { int err; - if ((err = pci_module_init(&driver)) > 0) + if ((err = pci_register_driver(&driver)) > 0) return err; return 0; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index f910399..4e63498 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -2401,7 +2401,7 @@ static struct pci_driver driver = { static int __init alsa_card_ens137x_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_ens137x_exit(void) diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index b4ca8ad..b492777 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1761,7 +1761,7 @@ static struct pci_driver driver = { static int __init alsa_card_es1938_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_es1938_exit(void) diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index faf63ff..da10d40 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2795,7 +2795,7 @@ static struct pci_driver driver = { static int __init alsa_card_es1968_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_es1968_exit(void) diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 3291434..ff10e63 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1469,7 +1469,7 @@ static struct pci_driver driver = { static int __init alsa_card_fm801_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_fm801_exit(void) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 959953c..cbc9ca7 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1439,7 +1439,7 @@ static struct pci_driver driver = { static int __init alsa_card_azx_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_azx_exit(void) diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 79fba6b..a2545a5 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2748,7 +2748,7 @@ static struct pci_driver driver = { static int __init alsa_card_ice1712_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_ice1712_exit(void) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 95500f0..79b5f12 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2328,7 +2328,7 @@ static struct pci_driver driver = { static int __init alsa_card_ice1724_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_ice1724_exit(void) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 8b33b12..9c5710d 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2849,7 +2849,7 @@ static struct pci_driver driver = { static int __init alsa_card_intel8x0_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_intel8x0_exit(void) diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index f9972b2..f655cf9 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1452,7 +1452,7 @@ static struct pci_driver driver = { static int __init alsa_card_intel8x0m_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_intel8x0m_exit(void) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index bb1de20..79d8eda 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2541,7 +2541,7 @@ static struct pci_driver driver = { static int __init alsa_card_korg1212_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_korg1212_exit(void) diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 2cf3308..9f184ea8 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2702,7 +2702,7 @@ static struct pci_driver driver = { static int __init alsa_card_m3_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_m3_exit(void) diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 65bb0f4..082c0d0 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1431,7 +1431,7 @@ static struct pci_driver driver = { static int __init alsa_card_mixart_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_mixart_exit(void) diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 356fbea..8a52091 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1645,7 +1645,7 @@ static struct pci_driver driver = { static int __init alsa_card_nm256_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_nm256_exit(void) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index b96acd5..b7b554d 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -2031,7 +2031,7 @@ static struct pci_driver driver = { static int __init alsa_card_rme32_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_rme32_exit(void) diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 8e26668..10c4f45 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -2437,7 +2437,7 @@ static struct pci_driver driver = { static int __init alsa_card_rme96_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_rme96_exit(void) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 12efbf0..44ca7dd 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -5194,7 +5194,7 @@ static struct pci_driver driver = { static int __init alsa_card_hdsp_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_hdsp_exit(void) diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 69cd81e..5861f23 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -2664,7 +2664,7 @@ static struct pci_driver driver = { static int __init alsa_card_hammerfall_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_hammerfall_exit(void) diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index cfd2c5f..60ecb2b 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -1522,7 +1522,7 @@ static struct pci_driver driver = { static int __init alsa_card_sonicvibes_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_sonicvibes_exit(void) diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index ad58e08..5d21cb8 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -184,7 +184,7 @@ static struct pci_driver driver = { static int __init alsa_card_trident_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_trident_exit(void) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index e6e746f..64cc40f 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2349,7 +2349,7 @@ static struct pci_driver driver = { static int __init alsa_card_via82xx_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_via82xx_exit(void) diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index ea5c6f6..098870a 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -1233,7 +1233,7 @@ static struct pci_driver driver = { static int __init alsa_card_via82xx_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_via82xx_exit(void) diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 4ffbb25..dca6bd2 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -260,7 +260,7 @@ static struct pci_driver driver = { static int __init alsa_card_vx222_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_vx222_exit(void) diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 9f3ef22..5b5b624 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -360,7 +360,7 @@ static struct pci_driver driver = { static int __init alsa_card_ymfpci_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_ymfpci_exit(void) -- cgit v0.10.2 From 0af68e5ed45e985b676edfbe4b8851dd46316502 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Apr 2005 17:03:03 +0200 Subject: [ALSA] Fix compile warning EMU10K1/EMU10K2 driver Fix compile warnings regarding the unused variables/functions. Signed-off-by: Takashi Iwai diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index b544c25..6be82c5 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -68,6 +68,7 @@ static int snd_emu10k1_spdif_get_mask(snd_kcontrol_t * kcontrol, return 0; } +#if 0 static int snd_audigy_spdif_output_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { static char *texts[] = {"44100", "48000", "96000"}; @@ -152,6 +153,7 @@ static snd_kcontrol_new_t snd_audigy_spdif_output_rate = .get = snd_audigy_spdif_output_rate_get, .put = snd_audigy_spdif_output_rate_put }; +#endif static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -- cgit v0.10.2 From bd7bf042e89941d4e693a0ec68c5093a2bb2adb3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Apr 2005 16:27:28 +0200 Subject: [ALSA] Fix permissions in some /proc files PCM Midlevel,CA0106 driver,EMU10K1/EMU10K2 driver Fix by Guillaume Chazarain : Some tunables in /proc have a write() function, but as their permission does not reflect it, it can be confusing to the user. So here is a patch that corrects the mode of those files. Note that I have only tested the 'xrun_debug' entry. Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8d94325..a2757fc 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -451,6 +451,7 @@ static int snd_pcm_stream_proc_init(snd_pcm_str_t *pstr) entry->c.text.read = snd_pcm_xrun_debug_read; entry->c.text.write_size = 64; entry->c.text.write = snd_pcm_xrun_debug_write; + entry->mode |= S_IWUSR; entry->private_data = pstr; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index f1d5f7a..9a174fb 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -204,6 +204,7 @@ static int snd_pcm_lib_preallocate_pages1(snd_pcm_substream_t *substream, entry->c.text.read = snd_pcm_lib_preallocate_proc_read; entry->c.text.write_size = 64; entry->c.text.write = snd_pcm_lib_preallocate_proc_write; + entry->mode |= S_IWUSR; entry->private_data = substream; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index afb7114..0bc1d78 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -418,6 +418,7 @@ int __devinit snd_ca0106_proc_init(ca0106_t * emu) snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read32); entry->c.text.write_size = 64; entry->c.text.write = snd_ca0106_proc_reg_write32; + entry->mode |= S_IWUSR; } if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry)) snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read16); @@ -427,6 +428,7 @@ int __devinit snd_ca0106_proc_init(ca0106_t * emu) snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read1); entry->c.text.write_size = 64; entry->c.text.write = snd_ca0106_proc_reg_write; + entry->mode |= S_IWUSR; // entry->private_data = emu; } if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 04ba637..f8d9233 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1075,6 +1075,7 @@ static int __devinit snd_emu10k1x_proc_init(emu10k1x_t * emu) snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read); entry->c.text.write_size = 64; entry->c.text.write = snd_emu10k1x_proc_reg_write; + entry->mode |= S_IWUSR; entry->private_data = emu; } diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 356fb71..cc22707 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -527,26 +527,31 @@ int __devinit snd_emu10k1_proc_init(emu10k1_t * emu) snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read); entry->c.text.write_size = 64; entry->c.text.write = snd_emu_proc_io_reg_write; + entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a); entry->c.text.write_size = 64; entry->c.text.write = snd_emu_proc_ptr_reg_write00; + entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b); entry->c.text.write_size = 64; entry->c.text.write = snd_emu_proc_ptr_reg_write00; + entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a); entry->c.text.write_size = 64; entry->c.text.write = snd_emu_proc_ptr_reg_write20; + entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b); entry->c.text.write_size = 64; entry->c.text.write = snd_emu_proc_ptr_reg_write20; + entry->mode |= S_IWUSR; } #endif -- cgit v0.10.2 From 004e65389714721ce0f52a8f0fc22999d3908a2a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Apr 2005 17:33:59 +0200 Subject: [ALSA] Fix capture on OSS emulation ALSA<-OSS emulation Fix the noisy capture on some hardwares over OSS emulation. Change back to avail_min = period_size for capture direction. Signed-off-by: Takashi Iwai diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 1a80502..6c8fdca 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -464,7 +464,8 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream) sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; sw_params->period_step = 1; sw_params->sleep_min = 0; - sw_params->avail_min = 1; + sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + 1 : runtime->period_size; sw_params->xfer_align = 1; if (atomic_read(&runtime->mmap_count) || (substream->oss.setup && substream->oss.setup->nosilence)) { -- cgit v0.10.2 From 267cdf4036ed9e8565a7d909fdf854b9c7e1c5ff Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 13 Apr 2005 13:25:30 +0200 Subject: [ALSA] replace SNDRV_PCM_HW_PARAMS_RUNTIME -> SNDRV_PCM_HW_PARAMS_NORESAMPLE ALSA Core Signed-off-by: Jaroslav Kysela diff --git a/include/sound/asound.h b/include/sound/asound.h index a4d149f..716227e 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -344,7 +344,7 @@ enum sndrv_pcm_hw_param { SNDRV_PCM_HW_PARAM_LAST_INTERVAL = SNDRV_PCM_HW_PARAM_TICK_TIME }; -#define SNDRV_PCM_HW_PARAMS_RUNTIME (1<<0) +#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */ struct sndrv_interval { unsigned int min, max; -- cgit v0.10.2 From eb8caf30f4c059ddfdfa32b6034549622953db6f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 13 Apr 2005 14:32:57 +0200 Subject: [ALSA] Improve the shared-jack handling on ac97 AC97 Codec The handling of shared surround/clfe output jacks with line/mic-in on some AC97 codecs is improved. Instead of 'Line-In As Surround' or 'Mic As Center/LFE' switch, two new enum controls are introduced: 'Channel Mode' and 'Surround Jack Mode'. The formar changes the current output mode among 2, 4 and 6-channels. The latter controls whether the jacks are shared or independent. Signed-off-by: Takashi Iwai diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 2433e27..996eeab 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -437,6 +437,7 @@ struct snd_ac97_build_ops { void (*suspend) (ac97_t *ac97); void (*resume) (ac97_t *ac97); #endif + void (*update_jacks) (ac97_t *ac97); /* for jack-sharing */ }; struct _snd_ac97_bus_ops { @@ -516,6 +517,9 @@ struct _snd_ac97 { } ad18xx; unsigned int dev_flags; /* device specific */ } spec; + /* jack-sharing info */ + unsigned char indep_surround; + unsigned char channel_mode; }; /* conditions */ diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 473840d..7f16c30 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -64,6 +64,116 @@ static int ac97_update_bits_page(ac97_t *ac97, unsigned short reg, unsigned shor return ret; } +/* + * shared line-in/mic controls + */ +static int ac97_enum_text_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo, + const char **texts, unsigned int nums) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = nums; + if (uinfo->value.enumerated.item > nums - 1) + uinfo->value.enumerated.item = nums - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int ac97_surround_jack_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static const char *texts[] = { "Shared", "Independent" }; + return ac97_enum_text_info(kcontrol, uinfo, texts, 2); +} + +static int ac97_surround_jack_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = ac97->indep_surround; + return 0; +} + +static int ac97_surround_jack_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned char indep = !!ucontrol->value.enumerated.item[0]; + + if (indep != ac97->indep_surround) { + ac97->indep_surround = indep; + if (ac97->build_ops->update_jacks) + ac97->build_ops->update_jacks(ac97); + return 1; + } + return 0; +} + +static int ac97_channel_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static const char *texts[] = { "2ch", "4ch", "6ch" }; + if (kcontrol->private_value) + return ac97_enum_text_info(kcontrol, uinfo, texts, 2); /* 4ch only */ + return ac97_enum_text_info(kcontrol, uinfo, texts, 3); +} + +static int ac97_channel_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = ac97->channel_mode; + return 0; +} + +static int ac97_channel_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned char mode = ucontrol->value.enumerated.item[0]; + + if (mode != ac97->channel_mode) { + ac97->channel_mode = mode; + if (ac97->build_ops->update_jacks) + ac97->build_ops->update_jacks(ac97); + return 1; + } + return 0; +} + +#define AC97_SURROUND_JACK_MODE_CTL \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Surround Jack Mode", \ + .info = ac97_surround_jack_mode_info, \ + .get = ac97_surround_jack_mode_get, \ + .put = ac97_surround_jack_mode_put, \ + } +#define AC97_CHANNEL_MODE_CTL \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Channel Mode", \ + .info = ac97_channel_mode_info, \ + .get = ac97_channel_mode_get, \ + .put = ac97_channel_mode_put, \ + } +#define AC97_CHANNEL_MODE_4CH_CTL \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Channel Mode", \ + .info = ac97_channel_mode_info, \ + .get = ac97_channel_mode_get, \ + .put = ac97_channel_mode_put, \ + .private_value = 1, \ + } + +static inline int is_shared_linein(ac97_t *ac97) +{ + return ! ac97->indep_surround && ac97->channel_mode >= 1; +} + +static inline int is_shared_micin(ac97_t *ac97) +{ + return ! ac97->indep_surround && ac97->channel_mode >= 2; +} + + /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ @@ -1390,6 +1500,16 @@ static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_va AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); } +static void ad1888_update_jacks(ac97_t *ac97) +{ + /* shared Line-In */ + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, + is_shared_linein(ac97) ? 0 : 1 << 12); + /* shared Mic */ + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, + is_shared_micin(ac97) ? 0 : 1 << 13); +} + static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1406,8 +1526,13 @@ static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { .get = snd_ac97_ad1888_downmix_get, .put = snd_ac97_ad1888_downmix_put }, +#if 0 AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), +#else + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, +#endif }; static int patch_ad1888_specific(ac97_t *ac97) @@ -1422,8 +1547,9 @@ static struct snd_ac97_build_ops patch_ad1888_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1888_specific, #ifdef CONFIG_PM - .resume = ad18xx_resume + .resume = ad18xx_resume, #endif + .update_jacks = ad1888_update_jacks, }; int patch_ad1888(ac97_t * ac97) @@ -1521,31 +1647,25 @@ int patch_ad1985(ac97_t * ac97) /* * realtek ALC65x/850 codecs */ -static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; - return 0; -} - -static int snd_ac97_alc650_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +static void alc650_update_jacks(ac97_t *ac97) { - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - int change, val; - val = !!(snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10)); - change = (ucontrol->value.integer.value[0] != val); - if (change) { - /* disable/enable vref */ - snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, - ucontrol->value.integer.value[0] ? (1 << 12) : 0); - /* turn on/off center-on-mic */ - snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, - ucontrol->value.integer.value[0] ? (1 << 10) : 0); - /* GPIO0 high for mic */ - snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, - ucontrol->value.integer.value[0] ? 0 : 0x100); - } - return change; + int shared; + + /* shared Line-In */ + shared = is_shared_linein(ac97); + snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9, + shared ? (1 << 9) : 0); + /* update shared Mic */ + shared = is_shared_micin(ac97); + /* disable/enable vref */ + snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, + shared ? (1 << 12) : 0); + /* turn on/off center-on-mic */ + snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, + shared ? (1 << 10) : 0); + /* GPIO0 high for mic */ + snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, + shared ? 0 : 0x100); } static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { @@ -1558,8 +1678,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { /* 6: Independent Master Volume Right */ /* 7: Independent Master Volume Left */ /* 8: reserved */ - AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), - /* 10: mic, see below */ + /* 9: Line-In/Surround share */ + /* 10: Mic/CLFE share */ /* 11-13: in IEC958 controls */ AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), #if 0 /* always set in patch_alc650 */ @@ -1570,14 +1690,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), #endif - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_volsw, - .get = snd_ac97_alc650_mic_get, - .put = snd_ac97_alc650_mic_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { @@ -1601,7 +1715,8 @@ static int patch_alc650_specific(ac97_t * ac97) } static struct snd_ac97_build_ops patch_alc650_ops = { - .build_specific = patch_alc650_specific + .build_specific = patch_alc650_specific, + .update_jacks = alc650_update_jacks }; int patch_alc650(ac97_t * ac97) @@ -1659,37 +1774,27 @@ int patch_alc650(ac97_t * ac97) return 0; } -static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; - return 0; -} - -static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +static void alc655_update_jacks(ac97_t *ac97) { - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - + int shared; + + /* shared Line-In */ + shared = is_shared_linein(ac97); + ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9, + shared ? (1 << 9) : 0, 0); + /* update shared mic */ + shared = is_shared_micin(ac97); /* misc control; vrefout disable */ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, - ucontrol->value.integer.value[0] ? (1 << 12) : 0); - return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, - ucontrol->value.integer.value[0] ? (1 << 10) : 0, - 0); + shared ? (1 << 12) : 0); + ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, + shared ? (1 << 10) : 0, 0); } - static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), - AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 0), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_volsw, - .get = snd_ac97_alc655_mic_get, - .put = snd_ac97_alc655_mic_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -1759,7 +1864,8 @@ static int patch_alc655_specific(ac97_t * ac97) } static struct snd_ac97_build_ops patch_alc655_ops = { - .build_specific = patch_alc655_specific + .build_specific = patch_alc655_specific, + .update_jacks = alc655_update_jacks }; int patch_alc655(ac97_t * ac97) @@ -1798,63 +1904,32 @@ int patch_alc655(ac97_t * ac97) #define AC97_ALC850_JACK_SELECT 0x76 #define AC97_ALC850_MISC1 0x7a -static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +static void alc850_update_jacks(ac97_t *ac97) { - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 12) & 7) == 2; - return 0; -} - -static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - + int shared; + + /* shared Line-In */ + shared = is_shared_linein(ac97); /* SURR 1kOhm (bit4), Amp (bit5) */ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), - ucontrol->value.integer.value[0] ? (1<<5) : (1<<4)); + shared ? (1<<5) : (1<<4)); /* LINE-IN = 0, SURROUND = 2 */ - return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, - ucontrol->value.integer.value[0] ? (2<<12) : (0<<12)); -} - -static int ac97_alc850_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 4) & 7) == 2; - return 0; -} - -static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - + snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, + shared ? (2<<12) : (0<<12)); + /* update shared mic */ + shared = is_shared_micin(ac97); /* Vref disable (bit12), 1kOhm (bit13) */ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), - ucontrol->value.integer.value[0] ? (1<<12) : (1<<13)); + shared ? (1<<12) : (1<<13)); /* MIC-IN = 1, CENTER-LFE = 2 */ - return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, - ucontrol->value.integer.value[0] ? (2<<4) : (1<<4)); + snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, + shared ? (2<<4) : (1<<4)); } static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line-In As Surround", - .info = snd_ac97_info_volsw, - .get = ac97_alc850_surround_get, - .put = ac97_alc850_surround_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_volsw, - .get = ac97_alc850_mic_get, - .put = ac97_alc850_mic_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, - + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static int patch_alc850_specific(ac97_t *ac97) @@ -1871,7 +1946,8 @@ static int patch_alc850_specific(ac97_t *ac97) } static struct snd_ac97_build_ops patch_alc850_ops = { - .build_specific = patch_alc850_specific + .build_specific = patch_alc850_specific, + .update_jacks = alc850_update_jacks }; int patch_alc850(ac97_t *ac97) @@ -1911,9 +1987,17 @@ int patch_alc850(ac97_t *ac97) /* * C-Media CM97xx codecs */ +static void cm9738_update_jacks(ac97_t *ac97) +{ + /* shared Line-In */ + snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10, + is_shared_linein(ac97) ? (1 << 10) : 0); +} + static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { - AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_4CH_CTL, }; static int patch_cm9738_specific(ac97_t * ac97) @@ -1922,7 +2006,8 @@ static int patch_cm9738_specific(ac97_t * ac97) } static struct snd_ac97_build_ops patch_cm9738_ops = { - .build_specific = patch_cm9738_specific + .build_specific = patch_cm9738_specific, + .update_jacks = cm9738_update_jacks }; int patch_cm9738(ac97_t * ac97) @@ -1986,34 +2071,19 @@ static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = { /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ }; -static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; - return 0; -} - -static int snd_ac97_cm9739_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static void cm9739_update_jacks(ac97_t *ac97) { - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, - ucontrol->value.integer.value[0] ? - 0x1000 : 0x2000); + /* shared Line-In */ + snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10, + is_shared_linein(ac97) ? (1 << 10) : 0); + /* shared Mic */ + snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, + is_shared_micin(ac97) ? 0x1000 : 0x2000); } static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { - AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_volsw, - .get = snd_ac97_cm9739_center_mic_get, - .put = snd_ac97_cm9739_center_mic_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static int patch_cm9739_specific(ac97_t * ac97) @@ -2028,7 +2098,8 @@ static int patch_cm9739_post_spdif(ac97_t * ac97) static struct snd_ac97_build_ops patch_cm9739_ops = { .build_specific = patch_cm9739_specific, - .build_post_spdif = patch_cm9739_post_spdif + .build_post_spdif = patch_cm9739_post_spdif, + .update_jacks = cm9739_update_jacks }; int patch_cm9739(ac97_t * ac97) @@ -2090,67 +2161,28 @@ int patch_cm9739(ac97_t * ac97) #define AC97_CM9761_FUNC 0x66 #define AC97_CM9761_SPDIF_CTRL 0x6c -static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static void cm9761_update_jacks(ac97_t *ac97) { - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x0400) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; - return 0; -} - -static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short vals[2][2] = { + unsigned short surr_vals[2][2] = { { 0x0008, 0x0400 }, /* off, on */ { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ }; - return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, - vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); -} - -static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x1000) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; - if (ac97->spec.dev_flags) /* 9761-82 rev.B */ - ucontrol->value.integer.value[0] = !ucontrol->value.integer.value[0]; - return 0; -} - -static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short vals[2][2] = { + unsigned short clfe_vals[2][2] = { { 0x2000, 0x1880 }, /* off, on */ { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ }; - return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, - vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); + + /* shared Line-In */ + snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, + surr_vals[ac97->spec.dev_flags][is_shared_linein(ac97)]); + /* shared Mic */ + snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, + clfe_vals[ac97->spec.dev_flags][is_shared_micin(ac97)]); } static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line-In As Surround", - .info = snd_ac97_info_volsw, - .get = snd_ac97_cm9761_linein_rear_get, - .put = snd_ac97_cm9761_linein_rear_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_volsw, - .get = snd_ac97_cm9761_center_mic_get, - .put = snd_ac97_cm9761_center_mic_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -2224,7 +2256,8 @@ static int patch_cm9761_specific(ac97_t * ac97) static struct snd_ac97_build_ops patch_cm9761_ops = { .build_specific = patch_cm9761_specific, - .build_post_spdif = patch_cm9761_post_spdif + .build_post_spdif = patch_cm9761_post_spdif, + .update_jacks = cm9761_update_jacks }; int patch_cm9761(ac97_t *ac97) @@ -2370,9 +2403,21 @@ int patch_vt1616(ac97_t * ac97) return 0; } +/* + */ +static void it2646_update_jacks(ac97_t *ac97) +{ + /* shared Line-In */ + snd_ac97_update_bits(ac97, 0x76, 1 << 9, + is_shared_linein(ac97) ? (1<<9) : 0); + /* shared Mic */ + snd_ac97_update_bits(ac97, 0x76, 1 << 10, + is_shared_micin(ac97) ? (1<<10) : 0); +} + static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { - AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0), - AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0), + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { @@ -2392,7 +2437,8 @@ static int patch_it2646_specific(ac97_t * ac97) } static struct snd_ac97_build_ops patch_it2646_ops = { - .build_specific = patch_it2646_specific + .build_specific = patch_it2646_specific, + .update_jacks = it2646_update_jacks }; int patch_it2646(ac97_t * ac97) -- cgit v0.10.2 From 1a12de1edf234b54ce94971d5604f85809c391b9 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 13 Apr 2005 14:37:50 +0200 Subject: [ALSA] hda: fix vref cap and ctl values HDA Codec driver,HDA generic driver Fix some vref defines so they are valid for the different bits in the pin cap and pin control registers. Please apply. Signed-off-by: Matt Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c9e9dc9..042bcfc6 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -176,15 +176,21 @@ enum { #define AC_PINCAP_OUT (1<<4) /* output capable */ #define AC_PINCAP_IN (1<<5) /* input capable */ #define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ -#define AC_PINCAP_VREF (7<<8) +#define AC_PINCAP_VREF (0x37<<8) #define AC_PINCAP_VREF_SHIFT 8 #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ -/* Vref status (used in pin cap and pin ctl) */ -#define AC_PIN_VREF_HIZ (1<<0) /* Hi-Z */ -#define AC_PIN_VREF_50 (1<<1) /* 50% */ -#define AC_PIN_VREF_GRD (1<<2) /* ground */ -#define AC_PIN_VREF_80 (1<<4) /* 80% */ -#define AC_PIN_VREF_100 (1<<5) /* 100% */ +/* Vref status (used in pin cap) */ +#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */ +#define AC_PINCAP_VREF_50 (1<<1) /* 50% */ +#define AC_PINCAP_VREF_GRD (1<<2) /* ground */ +#define AC_PINCAP_VREF_80 (1<<4) /* 80% */ +#define AC_PINCAP_VREF_100 (1<<5) /* 100% */ +/* Vref setting (used in pin ctl) */ +#define AC_PINCTL_VREF_HIZ (0) /* Hi-Z */ +#define AC_PINCTL_VREF_50 (1) /* 50% */ +#define AC_PINCTL_VREF_GRD (2) /* ground */ +#define AC_PINCTL_VREF_80 (4) /* 80% */ +#define AC_PINCTL_VREF_100 (5) /* 100% */ /* Amplifier capabilities */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 69f7b6c..c233e7f 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -426,7 +426,7 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) return "Line"; case AC_JACK_CD: if (pinctl) - *pinctl |= AC_PIN_VREF_GRD; + *pinctl |= AC_PINCTL_VREF_GRD; return "CD"; case AC_JACK_AUX: if ((location & 0x0f) == AC_JACK_LOC_FRONT) -- cgit v0.10.2 From 2f2f4251c9b123b2ab04da9e78ab6158535c2e38 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 13 Apr 2005 14:45:30 +0200 Subject: [ALSA] add sigmatel codec support HDA generic driver,HDA Codec driver Add initial SigmaTel codec support for 9200 and 922x. Note that this hda patch relies on the configuration default registers to be set correctly (normally by BIOS/firmware) in order for it to set up pin widgets properly. There's a test switch in the patch so it will work with the SigmaTel reference boards that are usually plugged into a system that doesn't set the configuration default registers. It supports 2 channel analog out and line/mic in. I plan to add >2 channel support and spdif support shortly. Please apply. Signed-off-by: Matt Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 570a59d..bd8cb33 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,5 +1,5 @@ snd-hda-intel-objs := hda_intel.o -snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o +snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o ifdef CONFIG_PROC_FS snd-hda-codec-objs += hda_proc.o endif diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9ed117a..be6cba3 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -51,6 +51,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { { 0x10ec, "Realtek" }, { 0x13f6, "C-Media" }, { 0x434d, "C-Media" }, + { 0x8384, "SigmaTel" }, {} /* terminator */ }; diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index cf6abce..a5de684 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h @@ -8,10 +8,13 @@ extern struct hda_codec_preset snd_hda_preset_realtek[]; extern struct hda_codec_preset snd_hda_preset_cmedia[]; /* Analog Devices codecs */ extern struct hda_codec_preset snd_hda_preset_analog[]; +/* SigmaTel codecs */ +extern struct hda_codec_preset snd_hda_preset_sigmatel[]; static const struct hda_codec_preset *hda_preset_tables[] = { snd_hda_preset_realtek, snd_hda_preset_cmedia, snd_hda_preset_analog, + snd_hda_preset_sigmatel, NULL }; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c new file mode 100644 index 0000000..1534e20 --- /dev/null +++ b/sound/pci/hda/patch_sigmatel.c @@ -0,0 +1,560 @@ +/* + * Universal Interface for Intel High Definition Audio Codec + * + * HD audio interface patch for SigmaTel STAC92xx + * + * Copyright (c) 2005 Embedded Alley Solutions, Inc. + * + * + * Based on patch_cmedia.c and patch_realtek.c + * Copyright (c) 2004 Takashi Iwai + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This driver is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + +#undef STAC_TEST + +struct sigmatel_spec { + /* playback */ + struct hda_multi_out multiout; + hda_nid_t playback_nid; + + /* capture */ + hda_nid_t *adc_nids; + hda_nid_t *mux_nids; + unsigned int num_adcs; + hda_nid_t capture_nid; + + /* power management*/ + hda_nid_t *pstate_nids; + unsigned int num_pstates; + + /* pin widgets */ + hda_nid_t *pin_nids; + unsigned int num_pins; +#ifdef STAC_TEST + unsigned int *pin_configs; +#endif + + /* codec specific stuff */ + struct hda_verb *init; + snd_kcontrol_new_t *mixer; + + /* capture source */ + const struct hda_input_mux *input_mux; + unsigned int cur_mux[2]; + + /* channel mode */ + unsigned int num_ch_modes; + unsigned int cur_ch_mode; + const struct sigmatel_channel_mode *channel_modes; + + struct hda_pcm pcm_rec[1]; /* PCM information */ +}; + +static hda_nid_t stac9200_adc_nids[1] = { + 0x03, +}; + +static hda_nid_t stac9200_mux_nids[1] = { + 0x0c, +}; + +static hda_nid_t stac9200_dac_nids[1] = { + 0x02, +}; + +static hda_nid_t stac9200_pstate_nids[3] = { + 0x01, 0x02, 0x03, +}; + +static hda_nid_t stac9200_pin_nids[8] = { + 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, +}; + +static hda_nid_t stac922x_adc_nids[2] = { + 0x06, 0x07, +}; + +static hda_nid_t stac922x_mux_nids[2] = { + 0x12, 0x13, +}; + +static hda_nid_t stac922x_dac_nids[4] = { + 0x02, 0x03, 0x04, 0x05, +}; + +static hda_nid_t stac922x_pstate_nids[7] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +}; + +static hda_nid_t stac922x_pin_nids[10] = { + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x15, 0x1b, +}; + +static int stac92xx_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + return snd_hda_input_mux_info(spec->input_mux, uinfo); +} + +static int stac92xx_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; + return 0; +} + +static int stac92xx_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); +} + +static struct hda_verb stac9200_ch2_init[] = { + /* set dac0mux for dac converter */ + { 0x07, 0x701, 0x00}, + {} +}; + +static struct hda_verb stac922x_ch2_init[] = { + /* set master volume and direct control */ + { 0x16, 0x70f, 0xff}, + {} +}; + +struct sigmatel_channel_mode { + unsigned int channels; + const struct hda_verb *sequence; +}; + +static snd_kcontrol_new_t stac9200_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .count = 1, + .info = stac92xx_mux_enum_info, + .get = stac92xx_mux_enum_get, + .put = stac92xx_mux_enum_put, + }, + HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Input Mux Volume", 0x0c, 0, HDA_OUTPUT), + { } /* end */ +}; + +static snd_kcontrol_new_t stac922x_mixer[] = { + HDA_CODEC_VOLUME("PCM Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x2, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .count = 1, + .info = stac92xx_mux_enum_info, + .get = stac92xx_mux_enum_get, + .put = stac92xx_mux_enum_put, + }, + HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static struct hda_input_mux stac9200_input_mux = { + .num_items = 5, + .items = { + { "Port B", 0x0 }, + { "Port C", 0x1 }, + { "Port D", 0x2 }, + { "Port A", 0x3 }, + { "CD", 0x4 }, + } +}; + +static struct hda_input_mux stac922x_input_mux = { + .num_items = 7, + .items = { + { "Port E", 0x0 }, + { "CD", 0x1 }, + { "Port F", 0x2 }, + { "Port B", 0x3 }, + { "Port C", 0x4 }, + { "Port D", 0x5 }, + { "Port A", 0x6 }, + } +}; + +static int stac92xx_build_controls(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + int err; + + err = snd_hda_add_new_ctls(codec, spec->mixer); + if (err < 0) + return err; + + return 0; +} + +#ifdef STAC_TEST +static unsigned int stac9200_pin_configs[8] = { + 0x40000100, 0x40000100, 0x0221401f, 0x01114010, + 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, +}; + +static unsigned int stac922x_pin_configs[14] = { + 0x40000100, 0x40000100, 0x40000100, 0x01114010, + 0x01813122, 0x40000100, 0x40000100, 0x40000100, + 0x40000100, 0x40000100, +}; + +static void stac92xx_set_config_regs(struct hda_codec *codec) +{ + int i; + struct sigmatel_spec *spec = codec->spec; + unsigned int pin_cfg; + + for (i=0; i < spec->num_pins; i++) { + snd_hda_codec_write(codec, spec->pin_nids[i], 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, + spec->pin_configs[i] & 0x000000ff); + snd_hda_codec_write(codec, spec->pin_nids[i], 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, + (spec->pin_configs[i] & 0x0000ff00) >> 8); + snd_hda_codec_write(codec, spec->pin_nids[i], 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, + (spec->pin_configs[i] & 0x00ff0000) >> 16); + snd_hda_codec_write(codec, spec->pin_nids[i], 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, + spec->pin_configs[i] >> 24); + pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0, + AC_VERB_GET_CONFIG_DEFAULT, + 0x00); + printk("pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg); + } +} +#endif + +static int stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, unsigned int value) +{ + unsigned int pin_ctl; + + pin_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0x00); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_ctl | value); + + return 0; +} + +static int stac92xx_set_vref(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int vref_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) >> AC_PINCAP_VREF_SHIFT; + unsigned int vref_ctl = AC_PINCTL_VREF_HIZ; + + if (vref_caps & AC_PINCAP_VREF_100) + vref_ctl = AC_PINCTL_VREF_100; + else if (vref_caps & AC_PINCAP_VREF_80) + vref_ctl = AC_PINCTL_VREF_80; + else if (vref_caps & AC_PINCAP_VREF_50) + vref_ctl = AC_PINCTL_VREF_50; + else if (vref_caps & AC_PINCAP_VREF_GRD) + vref_ctl = AC_PINCTL_VREF_GRD; + + stac92xx_set_pinctl(codec, nid, vref_ctl); + + return 0; +} + +static int stac92xx_config_pin(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_cfg) +{ + switch((pin_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) { + case AC_JACK_HP_OUT: + /* Enable HP amp */ + stac92xx_set_pinctl(codec, nid, AC_PINCTL_HP_EN); + /* Fall through */ + case AC_JACK_LINE_OUT: + case AC_JACK_SPEAKER: + /* Enable output */ + stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); + break; + case AC_JACK_MIC_IN: + /* Set vref */ + stac92xx_set_vref(codec, nid); + case AC_JACK_CD: + case AC_JACK_LINE_IN: + case AC_JACK_AUX: + /* Enable input */ + stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); + break; + } + + return 0; +} + +static int stac92xx_config_pins(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + int i; + unsigned int pin_cfg; + + for (i=0; i < spec->num_pins; i++) { + /* Default to disabled */ + snd_hda_codec_write(codec, spec->pin_nids[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + 0x00); + + pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0, + AC_VERB_GET_CONFIG_DEFAULT, + 0x00); + if (((pin_cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) == AC_JACK_PORT_NONE) + continue; /* Move on */ + + stac92xx_config_pin(codec, spec->pin_nids[i], pin_cfg); + } + + return 0; +} + +static int stac92xx_init(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + int i; + + for (i=0; i < spec->num_pstates; i++) + snd_hda_codec_write(codec, spec->pstate_nids[i], 0, + AC_VERB_SET_POWER_STATE, 0x00); + + mdelay(100); + + snd_hda_sequence_write(codec, spec->init); + +#ifdef STAC_TEST + stac92xx_set_config_regs(codec); +#endif + + stac92xx_config_pins(codec); + + return 0; +} + +/* + * Analog playback callbacks + */ +static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); +} + +static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, + format, substream); +} + +static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Analog capture callbacks + */ +static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], + stream_tag, 0, format); + return 0; +} + +static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); + return 0; +} + +static struct hda_pcm_stream stac92xx_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0x02, /* NID to query formats and rates */ + .ops = { + .open = stac92xx_playback_pcm_open, + .prepare = stac92xx_playback_pcm_prepare, + .cleanup = stac92xx_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream stac92xx_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x06, /* NID to query formats and rates */ + .ops = { + .prepare = stac92xx_capture_pcm_prepare, + .cleanup = stac92xx_capture_pcm_cleanup + }, +}; + +static int stac92xx_build_pcms(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + + codec->num_pcms = 1; + codec->pcm_info = info; + + info->name = "STAC92xx"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->playback_nid; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->capture_nid; + + return 0; +} + +static void stac92xx_free(struct hda_codec *codec) +{ + kfree(codec->spec); +} + +static struct hda_codec_ops stac92xx_patch_ops = { + .build_controls = stac92xx_build_controls, + .build_pcms = stac92xx_build_pcms, + .init = stac92xx_init, + .free = stac92xx_free, +}; + +static int patch_stac9200(struct hda_codec *codec) +{ + struct sigmatel_spec *spec; + + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = stac9200_dac_nids; + spec->adc_nids = stac9200_adc_nids; + spec->mux_nids = stac9200_mux_nids; + spec->input_mux = &stac9200_input_mux; + spec->pstate_nids = stac9200_pstate_nids; + spec->num_pstates = 3; + spec->pin_nids = stac9200_pin_nids; +#ifdef STAC_TEST + spec->pin_configs = stac9200_pin_configs; +#endif + spec->num_pins = 8; + spec->init = stac9200_ch2_init; + spec->mixer = stac9200_mixer; + spec->playback_nid = 0x02; + spec->capture_nid = 0x03; + + codec->patch_ops = stac92xx_patch_ops; + + return 0; +} + +static int patch_stac922x(struct hda_codec *codec) +{ + struct sigmatel_spec *spec; + + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 4; + spec->multiout.dac_nids = stac922x_dac_nids; + spec->adc_nids = stac922x_adc_nids; + spec->mux_nids = stac922x_mux_nids; + spec->input_mux = &stac922x_input_mux; + spec->pstate_nids = stac922x_pstate_nids; + spec->num_pstates = 7; + spec->pin_nids = stac922x_pin_nids; +#ifdef STAC_TEST + spec->pin_configs = stac922x_pin_configs; +#endif + spec->num_pins = 10; + spec->init = stac922x_ch2_init; + spec->mixer = stac922x_mixer; + spec->playback_nid = 0x02; + spec->capture_nid = 0x06; + + codec->patch_ops = stac92xx_patch_ops; + + return 0; +} + +/* + * patch entries + */ +struct hda_codec_preset snd_hda_preset_sigmatel[] = { + { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 }, + { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x }, + { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x }, + { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x }, + { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, + { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, + { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, + {} /* terminator */ +}; -- cgit v0.10.2 From 4a3fdf3dba80f332e6233e72bdbccdc6031fc92e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Apr 2005 13:35:51 +0200 Subject: [ALSA] Add AD1981HD and AD1983 support HDA Codec driver Added the support of AD1981HD and AD1983 codecs. Including the fix for AD1986A. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 75d2384..caa4869 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1,5 +1,5 @@ /* - * HD audio interface patch for AD1986A + * HD audio interface patch for AD1981HD, AD1983, AD1986A * * Copyright (c) 2005 Takashi Iwai * @@ -27,13 +27,239 @@ #include "hda_codec.h" #include "hda_local.h" -struct ad1986a_spec { +struct ad198x_spec { struct semaphore amp_mutex; /* PCM volume/mute control mutex */ struct hda_multi_out multiout; /* playback */ + hda_nid_t adc_nid; + const struct hda_input_mux *input_mux; unsigned int cur_mux; /* capture source */ + unsigned int spdif_route; + snd_kcontrol_new_t *mixers; + const struct hda_verb *init_verbs; struct hda_pcm pcm_rec[2]; /* PCM information */ }; +/* + * input MUX handling (common part) + */ +static int ad198x_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + + return snd_hda_input_mux_info(spec->input_mux, uinfo); +} + +static int ad198x_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->cur_mux; + return 0; +} + +static int ad198x_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + spec->adc_nid, &spec->cur_mux); +} + +/* + * initialization (common callbacks) + */ +static int ad198x_init(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + snd_hda_sequence_write(codec, spec->init_verbs); + return 0; +} + +static int ad198x_build_controls(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + int err; + + err = snd_hda_add_new_ctls(codec, spec->mixers); + if (err < 0) + return err; + if (spec->multiout.dig_out_nid) + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + if (err < 0) + return err; + return 0; +} + +/* + * Analog playback callbacks + */ +static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); +} + +static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, + format, substream); +} + +static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Digital out + */ +static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +/* + * Analog capture + */ +static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + snd_hda_codec_setup_stream(codec, spec->adc_nid, stream_tag, 0, format); + return 0; +} + +static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + snd_hda_codec_setup_stream(codec, spec->adc_nid, 0, 0, 0); + return 0; +} + + +/* + */ +static struct hda_pcm_stream ad198x_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 6, + .nid = 0, /* fill later */ + .ops = { + .open = ad198x_playback_pcm_open, + .prepare = ad198x_playback_pcm_prepare, + .cleanup = ad198x_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream ad198x_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .prepare = ad198x_capture_pcm_prepare, + .cleanup = ad198x_capture_pcm_cleanup + }, +}; + +static struct hda_pcm_stream ad198x_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .open = ad198x_dig_playback_pcm_open, + .close = ad198x_dig_playback_pcm_close + }, +}; + +static int ad198x_build_pcms(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + + codec->num_pcms = 1; + codec->pcm_info = info; + + info->name = "AD198x Analog"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nid; + + if (spec->multiout.dig_out_nid) { + info++; + codec->num_pcms++; + info->name = "AD198x Digital"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; + } + + return 0; +} + +static void ad198x_free(struct hda_codec *codec) +{ + kfree(codec->spec); +} + +#ifdef CONFIG_PM +static int ad198x_resume(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + + ad198x_init(codec); + snd_hda_resume_ctls(codec, spec->mixers); + snd_hda_resume_spdif_out(codec); + return 0; +} +#endif + +static struct hda_codec_ops ad198x_patch_ops = { + .build_controls = ad198x_build_controls, + .build_pcms = ad198x_build_pcms, + .init = ad198x_init, + .free = ad198x_free, +#ifdef CONFIG_PM + .resume = ad198x_resume, +#endif +}; + + +/* + * AD1986A specific + */ + #define AD1986A_SPDIF_OUT 0x02 #define AD1986A_FRONT_DAC 0x03 #define AD1986A_SURR_DAC 0x04 @@ -68,7 +294,7 @@ static struct hda_input_mux ad1986a_capture_source = { static int ad1986a_pcm_amp_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *ad = codec->spec; + struct ad198x_spec *ad = codec->spec; down(&ad->amp_mutex); snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); @@ -79,7 +305,7 @@ static int ad1986a_pcm_amp_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_ static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *ad = codec->spec; + struct ad198x_spec *ad = codec->spec; int i, change = 0; down(&ad->amp_mutex); @@ -97,7 +323,7 @@ static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_ static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *ad = codec->spec; + struct ad198x_spec *ad = codec->spec; down(&ad->amp_mutex); snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); @@ -108,7 +334,7 @@ static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t static int ad1986a_pcm_amp_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *ad = codec->spec; + struct ad198x_spec *ad = codec->spec; int i, change = 0; down(&ad->amp_mutex); @@ -122,32 +348,6 @@ static int ad1986a_pcm_amp_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t } /* - * input MUX handling - */ -static int ad1986a_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - return snd_hda_input_mux_info(&ad1986a_capture_source, uinfo); -} - -static int ad1986a_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->cur_mux; - return 0; -} - -static int ad1986a_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *spec = codec->spec; - - return snd_hda_input_mux_put(codec, &ad1986a_capture_source, ucontrol, - AD1986A_ADC, &spec->cur_mux); -} - -/* * mixers */ static snd_kcontrol_new_t ad1986a_mixers[] = { @@ -194,9 +394,9 @@ static snd_kcontrol_new_t ad1986a_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", - .info = ad1986a_mux_enum_info, - .get = ad1986a_mux_enum_get, - .put = ad1986a_mux_enum_put, + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, }, HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), { } /* end */ @@ -241,183 +441,328 @@ static struct hda_verb ad1986a_init_verbs[] = { {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* HP Pin */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* Front, Surround, CLFE Pins */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* Mono Pin */ + {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* Mic Pin */ + {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* Line, Aux, CD, Beep-In Pin */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, { } /* end */ }; -static int ad1986a_init(struct hda_codec *codec) +static int patch_ad1986a(struct hda_codec *codec) { - snd_hda_sequence_write(codec, ad1986a_init_verbs); - return 0; -} + struct ad198x_spec *spec; -static int ad1986a_build_controls(struct hda_codec *codec) -{ - int err; + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + init_MUTEX(&spec->amp_mutex); + codec->spec = spec; + + spec->multiout.max_channels = 6; + spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); + spec->multiout.dac_nids = ad1986a_dac_nids; + spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; + spec->adc_nid = AD1986A_ADC; + spec->input_mux = &ad1986a_capture_source; + spec->mixers = ad1986a_mixers; + spec->init_verbs = ad1986a_init_verbs; + + codec->patch_ops = ad198x_patch_ops; - err = snd_hda_add_new_ctls(codec, ad1986a_mixers); - if (err < 0) - return err; - err = snd_hda_create_spdif_out_ctls(codec, AD1986A_SPDIF_OUT); - if (err < 0) - return err; return 0; } /* - * Analog playback callbacks + * AD1983 specific */ -static int ad1986a_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - snd_pcm_substream_t *substream) -{ - struct ad1986a_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); -} -static int ad1986a_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - snd_pcm_substream_t *substream) -{ - struct ad1986a_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} +#define AD1983_SPDIF_OUT 0x02 +#define AD1983_DAC 0x03 +#define AD1983_ADC 0x04 -static int ad1986a_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - snd_pcm_substream_t *substream) -{ - struct ad1986a_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} +static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; + +static struct hda_input_mux ad1983_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x1 }, + { "Mix", 0x2 }, + { "Mix Mono", 0x3 }, + }, +}; /* - * Digital out + * SPDIF playback route */ -static int ad1986a_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - snd_pcm_substream_t *substream) +static int ad1983_spdif_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { - struct ad1986a_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); + static char *texts[] = { "PCM", "ADC" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; } -static int ad1986a_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - snd_pcm_substream_t *substream) +static int ad1983_spdif_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - struct ad1986a_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; -/* - * Analog capture - */ -static int ad1986a_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - snd_pcm_substream_t *substream) -{ - snd_hda_codec_setup_stream(codec, AD1986A_ADC, stream_tag, 0, format); + ucontrol->value.enumerated.item[0] = spec->spdif_route; return 0; } -static int ad1986a_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - snd_pcm_substream_t *substream) +static int ad1983_spdif_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - snd_hda_codec_setup_stream(codec, AD1986A_ADC, 0, 0, 0); + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + + if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { + spec->spdif_route = ucontrol->value.enumerated.item[0]; + snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0, + AC_VERB_SET_CONNECT_SEL, spec->spdif_route); + return 1; + } return 0; } - -/* - */ -static struct hda_pcm_stream ad1986a_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 6, - .nid = AD1986A_FRONT_DAC, /* NID to query formats and rates */ - .ops = { - .open = ad1986a_playback_pcm_open, - .prepare = ad1986a_playback_pcm_prepare, - .cleanup = ad1986a_playback_pcm_cleanup +static snd_kcontrol_new_t ad1983_mixers[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, }, -}; - -static struct hda_pcm_stream ad1986a_pcm_analog_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = AD1986A_ADC, /* NID to query formats and rates */ - .ops = { - .prepare = ad1986a_capture_pcm_prepare, - .cleanup = ad1986a_capture_pcm_cleanup + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Route", + .info = ad1983_spdif_route_info, + .get = ad1983_spdif_route_get, + .put = ad1983_spdif_route_put, }, + { } /* end */ }; -static struct hda_pcm_stream ad1986a_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = AD1986A_SPDIF_OUT, - .ops = { - .open = ad1986a_dig_playback_pcm_open, - .close = ad1986a_dig_playback_pcm_close - }, +static struct hda_verb ad1983_init_verbs[] = { + /* Front, HP, Mono; mute as default */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Beep, PCM, Mic, Line-In: mute */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Front, HP selectors; from Mix */ + {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* Mono selector; from Mix */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* Mic selector; Mic */ + {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* Line-in selector: Line-in */ + {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* Mic boost: 0dB */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* Record selector: mic */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* SPDIF route: PCM */ + {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* Front Pin */ + {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* HP Pin */ + {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* Mono Pin */ + {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* Mic Pin */ + {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* Line Pin */ + {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { } /* end */ }; -static int ad1986a_build_pcms(struct hda_codec *codec) +static int patch_ad1983(struct hda_codec *codec) { - struct ad1986a_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; + struct ad198x_spec *spec; - codec->num_pcms = 2; - codec->pcm_info = info; + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; - info->name = "AD1986A Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1986a_pcm_analog_capture; - info++; + init_MUTEX(&spec->amp_mutex); + codec->spec = spec; + + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); + spec->multiout.dac_nids = ad1983_dac_nids; + spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; + spec->adc_nid = AD1983_ADC; + spec->input_mux = &ad1983_capture_source; + spec->mixers = ad1983_mixers; + spec->init_verbs = ad1983_init_verbs; + spec->spdif_route = 0; - info->name = "AD1986A Digital"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_digital_playback; + codec->patch_ops = ad198x_patch_ops; return 0; } -static void ad1986a_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} -#ifdef CONFIG_PM -static int ad1986a_resume(struct hda_codec *codec) -{ - ad1986a_init(codec); - snd_hda_resume_ctls(codec, ad1986a_mixers); - snd_hda_resume_spdif_out(codec); - return 0; -} -#endif +/* + * AD1981 HD specific + */ -static struct hda_codec_ops ad1986a_patch_ops = { - .build_controls = ad1986a_build_controls, - .build_pcms = ad1986a_build_pcms, - .init = ad1986a_init, - .free = ad1986a_free, -#ifdef CONFIG_PM - .resume = ad1986a_resume, -#endif +#define AD1981_SPDIF_OUT 0x02 +#define AD1981_DAC 0x03 +#define AD1981_ADC 0x04 + +static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; + +/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ +static struct hda_input_mux ad1981_capture_source = { + .num_items = 7, + .items = { + { "Front Mic", 0x0 }, + { "Line", 0x1 }, + { "Mix", 0x2 }, + { "Mix Mono", 0x3 }, + { "CD", 0x4 }, + { "Mic", 0x6 }, + { "Aux", 0x7 }, + }, }; -static int patch_ad1986a(struct hda_codec *codec) +static snd_kcontrol_new_t ad1981_mixers[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + /* identical with AD1983 */ + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Route", + .info = ad1983_spdif_route_info, + .get = ad1983_spdif_route_get, + .put = ad1983_spdif_route_put, + }, + { } /* end */ +}; + +static struct hda_verb ad1981_init_verbs[] = { + /* Front, HP, Mono; mute as default */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Front, HP selectors; from Mix */ + {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* Mono selector; from Mix */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* Mic Mixer; select Front Mic */ + {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Mic boost: 0dB */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* Record selector: Front mic */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* SPDIF route: PCM */ + {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* Front Pin */ + {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* HP Pin */ + {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* Mono Pin */ + {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* Front & Rear Mic Pins */ + {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* Line Pin */ + {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* Digital Beep */ + {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Line-Out as Input: disabled */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + { } /* end */ +}; + +static int patch_ad1981(struct hda_codec *codec) { - struct ad1986a_spec *spec; + struct ad198x_spec *spec; spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -426,20 +771,28 @@ static int patch_ad1986a(struct hda_codec *codec) init_MUTEX(&spec->amp_mutex); codec->spec = spec; - spec->multiout.max_channels = 6; - spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); - spec->multiout.dac_nids = ad1986a_dac_nids; - spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); + spec->multiout.dac_nids = ad1981_dac_nids; + spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; + spec->adc_nid = AD1981_ADC; + spec->input_mux = &ad1981_capture_source; + spec->mixers = ad1981_mixers; + spec->init_verbs = ad1981_init_verbs; + spec->spdif_route = 0; - codec->patch_ops = ad1986a_patch_ops; + codec->patch_ops = ad198x_patch_ops; return 0; } + /* * patch entries */ struct hda_codec_preset snd_hda_preset_analog[] = { + { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, + { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, {} /* terminator */ }; -- cgit v0.10.2 From 01f66d2ccf83ee3ddc8276346f4e1113b9de50d9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Apr 2005 13:36:24 +0200 Subject: [ALSA] Remove dead code HDA Codec driver Removed the dead (duplicated) code. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index be6cba3..890b756 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1449,10 +1449,6 @@ static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream snd_assert(info->nid, return -EINVAL); info->ops.prepare = hda_pcm_default_prepare; } - if (info->ops.prepare == NULL) { - snd_assert(info->nid, return -EINVAL); - info->ops.prepare = hda_pcm_default_prepare; - } if (info->ops.cleanup == NULL) { snd_assert(info->nid, return -EINVAL); info->ops.cleanup = hda_pcm_default_cleanup; -- cgit v0.10.2 From 98f759a61639b40686e607ecc6fefacb4c249c82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Apr 2005 13:37:13 +0200 Subject: [ALSA] Misc clean up HDA Codec driver Misc clean up: move the definitions of constants for pinctl to a single place. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 042bcfc6..263f5b6 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -185,13 +185,6 @@ enum { #define AC_PINCAP_VREF_GRD (1<<2) /* ground */ #define AC_PINCAP_VREF_80 (1<<4) /* 80% */ #define AC_PINCAP_VREF_100 (1<<5) /* 100% */ -/* Vref setting (used in pin ctl) */ -#define AC_PINCTL_VREF_HIZ (0) /* Hi-Z */ -#define AC_PINCTL_VREF_50 (1) /* 50% */ -#define AC_PINCTL_VREF_GRD (2) /* ground */ -#define AC_PINCTL_VREF_80 (4) /* 80% */ -#define AC_PINCTL_VREF_100 (5) /* 100% */ - /* Amplifier capabilities */ #define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ @@ -254,6 +247,11 @@ enum { /* Pin widget control - 8bit */ #define AC_PINCTL_VREFEN (0x7<<0) +#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ +#define AC_PINCTL_VREF_50 1 /* 50% */ +#define AC_PINCTL_VREF_GRD 2 /* ground */ +#define AC_PINCTL_VREF_80 4 /* 80% */ +#define AC_PINCTL_VREF_100 5 /* 100% */ #define AC_PINCTL_IN_EN (1<<5) #define AC_PINCTL_OUT_EN (1<<6) #define AC_PINCTL_HP_EN (1<<7) -- cgit v0.10.2 From 07cf374169699d78721668b4e4bd02097c971f75 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Apr 2005 16:21:03 +0200 Subject: [ALSA] Increase timer protocol number ALSA Core Increase the timer protocl number (to distinguish the fix for TREAD ioctls). Signed-off-by: Takashi Iwai diff --git a/include/sound/asound.h b/include/sound/asound.h index 716227e..26db585 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -559,7 +559,7 @@ enum { * Timer section - /dev/snd/timer */ -#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2) +#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 3) enum sndrv_timer_class { SNDRV_TIMER_CLASS_NONE = -1, -- cgit v0.10.2 From 7358036cc6cb139d70d2b1898d29ecedc087fceb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 15 Apr 2005 13:51:48 +0200 Subject: [ALSA] Add dxs_support=5 for Insight P4-ITX VIA82xx driver Added dxs_support=5 entry for Insight P4-ITX. Signed-off-by: Takashi Iwai diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 64cc40f..881af1d 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2165,6 +2165,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ { .vendor = 0x1106, .device = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ { .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ + { .vendor = 0x1106, .device = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */ { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ -- cgit v0.10.2 From fe5ac9dcfe3b219209cf8e08347cce47658267d0 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 20 Apr 2005 10:03:31 +0200 Subject: [ALSA] trivial warning fix for emu10k1 EMU10K1/EMU10K2 driver When building with gcc -W sound/pci/emu10k1/emupcm.c produces this little warning in 2.6.12-rc2-mm3 : sound/pci/emu10k1/emupcm.c:265: warning: 'inline' is not at beginning of declaration No big deal, but trivial to fix. Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index d1c2a02..fd7cc38 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -262,7 +262,7 @@ static unsigned int emu10k1_select_interprom(unsigned int pitch_target) * * returns: cache invalidate size in samples */ -static int inline emu10k1_ccis(int stereo, int w_16) +static inline int emu10k1_ccis(int stereo, int w_16) { if (w_16) { return stereo ? 24 : 26; -- cgit v0.10.2 From 230cd5e24853ed4dd960461989b8ed0986d37a99 Mon Sep 17 00:00:00 2001 From: Karsten Wiese Date: Wed, 20 Apr 2005 10:12:35 +0200 Subject: [ALSA] prevent oops & dead keyboard on usb unplugging while the device is being used USB generic driver,USB USX2Y Without this patch, some usb kobjects, which are parents to the usx2y's kobjects can be freed before the usx2y's. This led to an oops in get_kobj_path_length() and a dead keyboard, when the usx2y's kobjects were freed. The patch ensures the correct sequence. Tested ok on kernel 2.6.12-rc2. Signed-off-by: Karsten Wiese Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 84b0bbd..aae6614 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3289,7 +3289,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) } usb_chip[chip->index] = NULL; up(®ister_mutex); - snd_card_free_in_thread(card); + snd_card_free(card); } else { up(®ister_mutex); } diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index b06a267..89ee8b7 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -1,6 +1,11 @@ /* * usbusy2y.c - ALSA USB US-428 Driver * +2005-04-14 Karsten Wiese + Version 0.8.7.2: + Call snd_card_free() instead of snd_card_free_in_thread() to prevent oops with dead keyboard symptom. + Tested ok with kernel 2.6.12-rc2. + 2004-12-14 Karsten Wiese Version 0.8.7.1: snd_pcm_open for rawusb pcm-devices now returns -EBUSY if called without rawusb's hwdep device being open. @@ -143,7 +148,7 @@ MODULE_AUTHOR("Karsten Wiese "); -MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.1"); +MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}"); @@ -430,8 +435,6 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) if (ptr) { usX2Ydev_t* usX2Y = usX2Y((snd_card_t*)ptr); struct list_head* p; - if (usX2Y->chip_status == USX2Y_STAT_CHIP_HUP) // on 2.6.1 kernel snd_usbmidi_disconnect() - return; // calls us back. better leave :-) . usX2Y->chip.shutdown = 1; usX2Y->chip_status = USX2Y_STAT_CHIP_HUP; usX2Y_unlinkSeq(&usX2Y->AS04); @@ -443,7 +446,7 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) } if (usX2Y->us428ctls_sharedmem) wake_up(&usX2Y->us428ctls_wait_queue_head); - snd_card_free_in_thread((snd_card_t*)ptr); + snd_card_free((snd_card_t*)ptr); } } -- cgit v0.10.2 From c31329257522bf66df56e279e20df6fc7abd1ea7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Apr 2005 13:43:00 +0200 Subject: [ALSA] Fix a typo in comments HDA generic driver Fix a typo in comments. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index c233e7f..bfbeff2 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -44,7 +44,7 @@ struct hda_gnode { struct list_head list; }; -/* pathc-specific record */ +/* patch-specific record */ struct hda_gspec { struct hda_gnode *dac_node; /* DAC node */ struct hda_gnode *out_pin_node; /* Output pin (Line-Out) node */ -- cgit v0.10.2 From b0c95f514a4057720958c9ea0113229468c94b2b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Apr 2005 13:44:08 +0200 Subject: [ALSA] Show PIN jack type HDA generic driver Show the jack type of each PIN default configuration entry. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 8c703ff..15df716 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -157,6 +157,7 @@ static const char *get_jack_color(u32 cfg) static void print_pin_caps(snd_info_buffer_t *buffer, struct hda_codec *codec, hda_nid_t nid) { + static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; static char *jack_types[16] = { "Line Out", "Speaker", "HP Out", "CD", "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", @@ -176,7 +177,8 @@ static void print_pin_caps(snd_info_buffer_t *buffer, snd_iprintf(buffer, " HP"); snd_iprintf(buffer, "\n"); caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - snd_iprintf(buffer, " Pin Default 0x%08x: %s at %s %s\n", caps, + snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, + jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], get_jack_location(caps)); -- cgit v0.10.2 From d21b37ea134921f807ebdbd19ae3cd00bb8bf2fc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Apr 2005 13:45:55 +0200 Subject: [ALSA] Fix and cleanup of CM9880 auto-configuration HDA Codec driver Fix and cleanup of CM9880 automatic PIN configuration. snd_hda_codec_setup_stream() doesn't do anything when NID is 0. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 890b756..44fac21 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -549,6 +549,9 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format) { + if (! nid) + return; + snd_printdd("hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", nid, stream_tag, channel_id, format); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 263f5b6..43fc245 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -259,7 +259,9 @@ enum { /* configuration default - 32bit */ #define AC_DEFCFG_SEQUENCE (0xf<<0) #define AC_DEFCFG_DEF_ASSOC (0xf<<4) +#define AC_DEFCFG_ASSOC_SHIFT 4 #define AC_DEFCFG_MISC (0xf<<8) +#define AC_DEFCFG_MISC_SHIFT 8 #define AC_DEFCFG_COLOR (0xf<<12) #define AC_DEFCFG_COLOR_SHIFT 12 #define AC_DEFCFG_CONN_TYPE (0xf<<16) diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index e64e29d..087230c 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -365,7 +365,6 @@ static int cmi9880_build_controls(struct hda_codec *codec) return 0; } -#define AC_DEFCFG_ASSOC_SHIFT 4 #define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) #define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) #define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) @@ -796,6 +795,7 @@ static int patch_cmi9880(struct hda_codec *codec) { unsigned int port_e, port_f, port_g, port_h; unsigned int port_spdifi, port_spdifo; + int max_channels; /* collect pin default configuration */ cmi9880_get_pin_def_config(codec); port_e = cmi9880_get_def_config(codec, 0x0f); @@ -805,33 +805,40 @@ static int patch_cmi9880(struct hda_codec *codec) port_spdifi = cmi9880_get_def_config(codec, 0x13); port_spdifo = cmi9880_get_def_config(codec, 0x12); spec->front_panel = 1; - if ((get_defcfg_connect(port_e) == AC_JACK_PORT_NONE) - || (get_defcfg_connect(port_f) == AC_JACK_PORT_NONE)) { + if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || + get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { spec->surr_switch = 1; /* no front panel */ - if ((get_defcfg_connect(port_g) == AC_JACK_PORT_NONE) - || (get_defcfg_connect(port_h) == AC_JACK_PORT_NONE)) { + if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || + get_defcfg_connect(port_h) == AC_JACK_PORT_NONE) { /* no optional rear panel */ spec->board_config = CMI_MINIMAL; spec->front_panel = 0; spec->num_ch_modes = 2; - } else + } else { spec->board_config = CMI_MIN_FP; spec->num_ch_modes = 3; + } spec->channel_modes = cmi9880_channel_modes; spec->input_mux = &cmi9880_basic_mux; + spec->multiout.max_channels = cmi9880_channel_modes[0].channels; } else { spec->input_mux = &cmi9880_basic_mux; - if (get_defcfg_connect(port_spdifo) != 1) + if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - if (get_defcfg_connect(port_spdifi) != 1) + if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) spec->dig_in_nid = CMI_DIG_IN_NID; + spec->multiout.max_channels = 8; } - spec->multiout.max_channels = cmi9880_get_multich_pins(codec); - cmi9880_fill_multi_dac_nids(codec); - cmi9880_fill_multi_init(codec); - } + max_channels = cmi9880_get_multich_pins(codec); + if (max_channels > 0) { + spec->multiout.max_channels = max_channels; + cmi9880_fill_multi_dac_nids(codec); + cmi9880_fill_multi_init(codec); + } else + snd_printd("patch_cmedia: cannot detect association in defcfg\n"); break; + } } spec->multiout.num_dacs = 4; -- cgit v0.10.2 From 930fed517441310a80e269a193ee52f99dd58082 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Apr 2005 20:54:43 +0200 Subject: [ALSA] Add dxs_support entry for MSI K8T Neo-FIS2R VIA82xx driver Report by Ronny V. Vindenes Add dxs_support=5 for MSI K8T Neo-FIS2R. Signed-off-by: Takashi Iwai diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 881af1d..4c41df0 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2169,6 +2169,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ + { .vendor = 0x1462, .device = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */ { .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ { .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ { .vendor = 0x1462, .device = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */ -- cgit v0.10.2 From 863ad944b9a32dc43baa76143275411824d5928e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 22 Apr 2005 08:52:03 +0200 Subject: [ALSA] usb-audio: add Audigy 2 NX control names USB generic driver Add a mixer control map for the SB Audigy 2 NX so that we get meaningful mixer control names. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 1e994c9..4918a18 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -118,6 +118,50 @@ static struct usbmix_name_map mp3plus_map[] = { { 0 } /* terminator */ }; +/* Topology of SB Audigy 2 NX + + +----------------------------->EU[27]--+ + | v + | +----------------------------------->SU[29]---->FU[22]-->Dig_OUT[24] + | | ^ +USB_IN[1]-+------------+ +->EU[17]->+->FU[11]-+ + | v | v | +Dig_IN[4]---+->FU[6]-->MU[16]->FU[18]-+->EU[21]->SU[31]----->FU[30]->Hph_OUT[20] + | ^ | | +Lin_IN[7]-+--->FU[8]---+ +->EU[23]->FU[28]------------->Spk_OUT[19] + | | v + +--->FU[12]------------------------------------->SU[14]--->USB_OUT[15] + | ^ + +->FU[13]--------------------------------------+ +*/ +static struct usbmix_name_map audigy2nx_map[] = { + /* 1: IT pcm playback */ + /* 4: IT digital in */ + { 6, "Digital In Playback" }, /* FU */ + /* 7: IT line in */ + { 8, "Line Playback" }, /* FU */ + { 11, "What-U-Hear Capture" }, /* FU */ + { 12, "Line Capture" }, /* FU */ + { 13, "Digital In Capture" }, /* FU */ + { 14, "Capture Source" }, /* SU */ + /* 15: OT pcm capture */ + /* 16: MU w/o controls */ + { 17, NULL }, /* DISABLED: EU (for what?) */ + { 18, "Master Playback" }, /* FU */ + /* 19: OT speaker */ + /* 20: OT headphone */ + { 21, NULL }, /* DISABLED: EU (for what?) */ + { 22, "Digital Out Playback" }, /* FU */ + { 23, NULL }, /* DISABLED: EU (for what?) */ + /* 24: OT digital out */ + { 27, NULL }, /* DISABLED: EU (for what?) */ + { 28, "Speaker Playback" }, /* FU */ + { 29, "Digital Out Source" }, /* SU */ + { 30, "Headphone Playback" }, /* FU */ + { 31, "Headphone Source" }, /* SU */ + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -156,6 +200,7 @@ static struct usbmix_name_map justlink_map[] = { static struct usbmix_ctl_map usbmix_ctl_maps[] = { { 0x41e, 0x3000, extigy_map, 1 }, { 0x41e, 0x3010, mp3plus_map, 0 }, + { 0x41e, 0x3020, audigy2nx_map, 0 }, { 0x8bb, 0x2702, linex_map, 1 }, { 0xc45, 0x1158, justlink_map, 0 }, { 0 } /* terminator */ -- cgit v0.10.2 From 08fe15899df9696a6d34abf96230ae0691f5de66 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 22 Apr 2005 15:33:01 +0200 Subject: [ALSA] usb-audio - show exact synchronous frequency in proc file USB generic driver In the streamX proc file, show the exact number of samples per USB frame as 16.16 hexadecimal floating point value. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index aae6614..a7183c5 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1990,10 +1990,11 @@ static void proc_dump_substream_status(snd_usb_substream_t *subs, snd_info_buffe snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); snd_iprintf(buffer, "]\n"); snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); - snd_iprintf(buffer, " Momentary freq = %u Hz\n", + snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", snd_usb_get_speed(subs->dev) == USB_SPEED_FULL ? get_full_speed_hz(subs->freqm) - : get_high_speed_hz(subs->freqm)); + : get_high_speed_hz(subs->freqm), + subs->freqm >> 16, subs->freqm & 0xffff); } else { snd_iprintf(buffer, " Status: Stop\n"); } -- cgit v0.10.2 From 8e062ec7108f8a91149e6bccddc3b7341e406274 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 22 Apr 2005 15:49:52 +0200 Subject: [ALSA] usb-audio - add selector unit names override for Audigy 2 NX USB generic driver Add a mechanism to specify source names of selector units, and add such names for the SB Audigy 2 NX. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 5f19069..6ad154a 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -70,6 +70,7 @@ struct usb_mixer_build { DECLARE_BITMAP(unitbitmap, 32*32); usb_audio_term_t oterm; const struct usbmix_name_map *map; + const struct usbmix_selector_map *selector_map; }; struct usb_mixer_elem_info { @@ -187,6 +188,21 @@ static int check_ignored_ctl(mixer_build_t *state, int unitid, int control) return 0; } +/* get the mapped selector source name */ +static int check_mapped_selector_name(mixer_build_t *state, int unitid, + int index, char *buf, int buflen) +{ + const struct usbmix_selector_map *p; + + if (! state->selector_map) + return 0; + for (p = state->selector_map; p->id; p++) { + if (p->id == unitid && index < p->count) + return strlcpy(buf, p->names[index], buflen); + } + return 0; +} + /* * find an audio control unit with the given unit id */ @@ -1415,7 +1431,9 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned kfree(cval); return -ENOMEM; } - if (check_input_term(state, desc[5 + i], &iterm) >= 0) + len = check_mapped_selector_name(state, unitid, i, namelist[i], + MAX_ITEM_NAME_LEN); + if (! len && check_input_term(state, desc[5 + i], &iterm) >= 0) len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0); if (! len) sprintf(namelist[i], "Input %d", i); @@ -1521,6 +1539,7 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) for (map = usbmix_ctl_maps; map->vendor; map++) { if (map->vendor == state.vendor && map->product == state.product) { state.map = map->map; + state.selector_map = map->selector_map; chip->ignore_ctl_error = map->ignore_ctl_error; break; } diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 4918a18..adb0abb 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -26,10 +26,17 @@ struct usbmix_name_map { int control; }; +struct usbmix_selector_map { + int id; + int count; + const char **names; +}; + struct usbmix_ctl_map { int vendor; int product; const struct usbmix_name_map *map; + const struct usbmix_selector_map *selector_map; int ignore_ctl_error; }; @@ -162,6 +169,25 @@ static struct usbmix_name_map audigy2nx_map[] = { { 0 } /* terminator */ }; +static struct usbmix_selector_map audigy2nx_selectors[] = { + { + .id = 14, /* Capture Source */ + .count = 3, + .names = (const char*[]) {"Line", "Digital In", "What-U-Hear"} + }, + { + .id = 29, /* Digital Out Source */ + .count = 3, + .names = (const char*[]) {"Front", "PCM", "Digital In"} + }, + { + .id = 31, /* Headphone Source */ + .count = 2, + .names = (const char*[]) {"Front", "Side"} + }, + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -198,11 +224,29 @@ static struct usbmix_name_map justlink_map[] = { */ static struct usbmix_ctl_map usbmix_ctl_maps[] = { - { 0x41e, 0x3000, extigy_map, 1 }, - { 0x41e, 0x3010, mp3plus_map, 0 }, - { 0x41e, 0x3020, audigy2nx_map, 0 }, - { 0x8bb, 0x2702, linex_map, 1 }, - { 0xc45, 0x1158, justlink_map, 0 }, + { + .vendor = 0x41e, .product = 0x3000, + .map = extigy_map, + .ignore_ctl_error = 1, + }, + { + .vendor = 0x41e, .product = 0x3010, + .map = mp3plus_map, + }, + { + .vendor = 0x41e, .product = 0x3020, + .map = audigy2nx_map, + .selector_map = audigy2nx_selectors, + }, + { + .vendor = 0x8bb, .product = 0x2702, + .map = linex_map, + .ignore_ctl_error = 1, + }, + { + .vendor = 0xc45, .product = 0x1158, + .map = justlink_map, + }, { 0 } /* terminator */ }; -- cgit v0.10.2 From ee7333970bee3e7565feeb3edfef4db81cbe72e5 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 25 Apr 2005 10:34:13 +0200 Subject: [ALSA] usb-audio - remove superfluous parameter USB generic driver,USB USX2Y This patch removes the superfluous driver parameter from the disconnect functions. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a7183c5..08c5efc 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2588,7 +2588,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) * disconnect streams * called from snd_usb_audio_disconnect() */ -static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver *driver) +static void snd_usb_stream_disconnect(struct list_head *head) { int idx; snd_usb_stream_t *as; @@ -3282,11 +3282,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) snd_card_disconnect(card); /* release the pcm resources */ list_for_each(p, &chip->pcm_list) { - snd_usb_stream_disconnect(p, &usb_audio_driver); + snd_usb_stream_disconnect(p); } /* release the midi resources */ list_for_each(p, &chip->midi_list) { - snd_usbmidi_disconnect(p, &usb_audio_driver); + snd_usbmidi_disconnect(p); } usb_chip[chip->index] = NULL; up(®ister_mutex); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index eecbf19..14f7cf7 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -223,7 +223,7 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif); int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk); void snd_usbmidi_input_stop(struct list_head* p); void snd_usbmidi_input_start(struct list_head* p); -void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver); +void snd_usbmidi_disconnect(struct list_head *p); /* * retrieve usb_interface descriptor from the host interface diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 600d990..304a134 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -912,7 +912,7 @@ static void snd_usbmidi_free(snd_usb_midi_t* umidi) /* * Unlinks all URBs (must be done before the usb_device is deleted). */ -void snd_usbmidi_disconnect(struct list_head* p, struct usb_driver *driver) +void snd_usbmidi_disconnect(struct list_head* p) { snd_usb_midi_t* umidi; int i; diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 89ee8b7..e6e6da1 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -442,7 +442,7 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) snd_card_disconnect((snd_card_t*)ptr); /* release the midi resources */ list_for_each(p, &usX2Y->chip.midi_list) { - snd_usbmidi_disconnect(p, &snd_usX2Y_usb_driver); + snd_usbmidi_disconnect(p); } if (usX2Y->us428ctls_sharedmem) wake_up(&usX2Y->us428ctls_wait_queue_head); -- cgit v0.10.2 From b16760bbb9e3c63b6beef7e2c8f8db64ab5efe70 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Mon, 25 Apr 2005 11:22:20 +0200 Subject: [ALSA] fix behaviour of ac97_enum_mixer elements AC97 Codec ac97_enum mixer elements (e.g., 'Capture Source') did not work because of wrong bitmask calculation in snd_ac97_get_enum_double() and snd_ac97_put_enum_double(). https://bugtrack.alsa-project.org/alsa-bug/view.php?id=1072 Signed-off-by: Sergey Vlasov Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 1ad7f83..36a33ae 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -465,7 +465,7 @@ int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; unsigned short val, bitmask; - for (bitmask = 1; bitmask > e->mask; bitmask <<= 1) + for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) ; val = snd_ac97_read_cache(ac97, e->reg); ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); @@ -482,7 +482,7 @@ int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u unsigned short val; unsigned short mask, bitmask; - for (bitmask = 1; bitmask > e->mask; bitmask <<= 1) + for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) ; if (ucontrol->value.enumerated.item[0] > e->mask - 1) return -EINVAL; -- cgit v0.10.2 From 67e1b51e293cec9bbe8c9ad81680bceec1e3b7f9 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Mon, 25 Apr 2005 11:34:33 +0200 Subject: [ALSA] ac97 - add the 'Mic Front Input Switch' control (ALC850) AC97 Codec Add the 'Mic Front Input Switch' control to the mixer for ALC850. Enabling this input is required for using the front panel microphone connector with ASUS A8V motherboard. Signed-off-by: Sergey Vlasov Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 7f16c30..737c4bb 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1928,6 +1928,7 @@ static void alc850_update_jacks(ac97_t *ac97) static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), + AC97_SINGLE("Mic Front Input Switch", AC97_ALC850_JACK_SELECT, 15, 1, 1), AC97_SURROUND_JACK_MODE_CTL, AC97_CHANNEL_MODE_CTL, }; -- cgit v0.10.2 From 7679a03099992d8e6c878d459e22b639ed8c10fa Mon Sep 17 00:00:00 2001 From: Thomas Charbonnel Date: Mon, 25 Apr 2005 11:35:29 +0200 Subject: [ALSA] hdsp - solved big endian problem RME HDSP driver ppc firmware upload fix Signed-off-by: Thomas Charbonnel Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 44ca7dd..b35ed5f 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -4912,19 +4912,9 @@ static int __devinit hdsp_request_fw_loader(hdsp_t *hdsp) release_firmware(fw); return -EINVAL; } -#ifdef SNDRV_BIG_ENDIAN - { - int i; - u32 *src = (u32*)fw->data; - for (i = 0; i < ARRAY_SIZE(hdsp->firmware_cache); i++, src++) - hdsp->firmware_cache[i] = ((*src & 0x000000ff) << 16) | - ((*src & 0x0000ff00) << 8) | - ((*src & 0x00ff0000) >> 8) | - ((*src & 0xff000000) >> 16); - } -#else + memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache)); -#endif + release_firmware(fw); hdsp->state |= HDSP_FirmwareCached; -- cgit v0.10.2 From ade2916109dc53350298f1ccfb8ab03432c590b4 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 27 Apr 2005 16:09:21 +0200 Subject: ALSA CVS update ALSA Version 1.0.9rc3 Signed-off-by: Jaroslav Kysela diff --git a/include/sound/version.h b/include/sound/version.h index 98b4230..f5959de 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h. Generated by configure. */ -#define CONFIG_SND_VERSION "1.0.9rc2" +#define CONFIG_SND_VERSION "1.0.9rc3" #define CONFIG_SND_DATE " (Thu Mar 24 10:33:39 2005 UTC)" -- cgit v0.10.2 From 8c1872dcf29e2a194197e1d5a9c366a265986b84 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 28 Apr 2005 09:31:53 +0200 Subject: [ALSA] usb-audio - restrict Audigy 2 NX frequencies to 48/96 kHz USB generic driver On the SB Audigy 2 NX, frequency feedback doesn't quite work when playing at 44.1 kHz, so temporarily disable this frequency. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 08c5efc..e4b9104 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2422,15 +2422,17 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, if (err < 0) return err; #if 1 - /* FIXME: temporary hack for extigy */ + /* FIXME: temporary hack for extigy/audigy 2 nx */ /* extigy apparently supports sample rates other than 48k * but not in ordinary way. so we enable only 48k atm. */ if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - le16_to_cpu(dev->descriptor.idProduct) == 0x3000) { + (le16_to_cpu(dev->descriptor.idProduct) == 0x3000 || + le16_to_cpu(dev->descriptor.idProduct) == 0x3020)) { if (fmt[3] == USB_FORMAT_TYPE_I && stream == SNDRV_PCM_STREAM_PLAYBACK && - fp->rates != SNDRV_PCM_RATE_48000) + fp->rates != SNDRV_PCM_RATE_48000 && + fp->rates != SNDRV_PCM_RATE_96000) return -1; /* use 48k only */ } #endif -- cgit v0.10.2 From 707e60732fc25fe3760f916d083b262a86a666c0 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 09:56:17 +0200 Subject: [ALSA] usb-audio - reduce size of unitbitmap array USB generic driver Unit/terminal IDs are 8-bit integers, so the unitbitmap variable does not need to be bigger than 256 bits. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 6ad154a..e601f4b 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -67,7 +67,7 @@ struct usb_mixer_build { unsigned int ctrlif; unsigned short vendor; unsigned short product; - DECLARE_BITMAP(unitbitmap, 32*32); + DECLARE_BITMAP(unitbitmap, 256); usb_audio_term_t oterm; const struct usbmix_name_map *map; const struct usbmix_selector_map *selector_map; -- cgit v0.10.2 From 84957a8ab086377a025e0448fa716ed5983f3c3a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 16:23:13 +0200 Subject: [ALSA] usb-audio - move mixer data into separate struct USB generic driver Move all data related to audio control interfaces into a separate struct local to usbmixer.c. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index e4b9104..eeb09bb 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3091,6 +3091,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, chip->card = card; INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->midi_list); + INIT_LIST_HEAD(&chip->mixer_list); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_usb_audio_free(chip); @@ -3290,6 +3291,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) list_for_each(p, &chip->midi_list) { snd_usbmidi_disconnect(p); } + /* release mixer resources */ + list_for_each(p, &chip->mixer_list) { + snd_usb_mixer_disconnect(p); + } usb_chip[chip->index] = NULL; up(®ister_mutex); snd_card_free(card); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 14f7cf7..41d842d 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -136,7 +136,7 @@ struct snd_usb_audio { struct list_head midi_list; /* list of midi interfaces */ int next_midi_device; - unsigned int ignore_ctl_error; /* for mixer */ + struct list_head mixer_list; /* list of mixer interfaces */ }; /* @@ -219,6 +219,7 @@ void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsub int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout); int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif); +void snd_usb_mixer_disconnect(struct list_head *p); int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk); void snd_usbmidi_input_stop(struct list_head* p); diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index e601f4b..7bbcceb 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -50,6 +50,14 @@ typedef struct usb_audio_term usb_audio_term_t; typedef struct usb_mixer_elem_info usb_mixer_elem_info_t; +struct usb_mixer_interface { + snd_usb_audio_t *chip; + unsigned int ctrlif; + struct list_head list; + unsigned int ignore_ctl_error; +}; + + struct usb_audio_term { int id; int type; @@ -62,9 +70,9 @@ struct usbmix_name_map; struct usb_mixer_build { snd_usb_audio_t *chip; + struct usb_mixer_interface *mixer; unsigned char *buffer; unsigned int buflen; - unsigned int ctrlif; unsigned short vendor; unsigned short product; DECLARE_BITMAP(unitbitmap, 256); @@ -74,8 +82,7 @@ struct usb_mixer_build { }; struct usb_mixer_elem_info { - snd_usb_audio_t *chip; - unsigned int ctrlif; + struct usb_mixer_interface *mixer; unsigned int id; unsigned int control; /* CS or ICN (high byte) */ unsigned int cmask; /* channel mask bitmap: 0 = master */ @@ -317,16 +324,18 @@ static int get_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i int timeout = 10; while (timeout-- > 0) { - if (snd_usb_ctl_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0), + if (snd_usb_ctl_msg(cval->mixer->chip->dev, + usb_rcvctrlpipe(cval->mixer->chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx, cval->ctrlif | (cval->id << 8), + validx, cval->mixer->ctrlif | (cval->id << 8), buf, val_len, 100) >= 0) { *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); return 0; } } - snd_printdd(KERN_ERR "cannot get ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type); + snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", + request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); return -EINVAL; } @@ -355,13 +364,15 @@ static int set_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i buf[0] = value_set & 0xff; buf[1] = (value_set >> 8) & 0xff; while (timeout -- > 0) - if (snd_usb_ctl_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0), + if (snd_usb_ctl_msg(cval->mixer->chip->dev, + usb_sndctrlpipe(cval->mixer->chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - validx, cval->ctrlif | (cval->id << 8), + validx, cval->mixer->ctrlif | (cval->id << 8), buf, val_len, 100) >= 0) return 0; - snd_printdd(KERN_ERR "cannot set ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d, data = 0x%x/0x%x\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]); + snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", + request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]); return -EINVAL; } @@ -401,12 +412,13 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou * if failed, give up and free the control instance. */ -static int add_control_to_empty(snd_card_t *card, snd_kcontrol_t *kctl) +static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) { int err; - while (snd_ctl_find_id(card, &kctl->id)) + + while (snd_ctl_find_id(state->chip->card, &kctl->id)) kctl->id.index++; - if ((err = snd_ctl_add(card, kctl)) < 0) { + if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); snd_ctl_free_one(kctl); } @@ -624,7 +636,8 @@ static int get_min_max(usb_mixer_elem_info_t *cval, int default_min) } if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { - snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", cval->id, cval->ctrlif, cval->control, cval->id); + snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", + cval->id, cval->mixer->ctrlif, cval->control, cval->id); return -EINVAL; } if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { @@ -684,7 +697,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t if (cval->cmask & (1 << c)) { err = get_cur_mix_value(cval, c + 1, &val); if (err < 0) { - if (cval->chip->ignore_ctl_error) { + if (cval->mixer->ignore_ctl_error) { ucontrol->value.integer.value[0] = cval->min; return 0; } @@ -700,7 +713,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t /* master channel */ err = get_cur_mix_value(cval, 0, &val); if (err < 0) { - if (cval->chip->ignore_ctl_error) { + if (cval->mixer->ignore_ctl_error) { ucontrol->value.integer.value[0] = cval->min; return 0; } @@ -726,7 +739,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t if (cval->cmask & (1 << c)) { err = get_cur_mix_value(cval, c + 1, &oval); if (err < 0) { - if (cval->chip->ignore_ctl_error) + if (cval->mixer->ignore_ctl_error) return 0; return err; } @@ -743,7 +756,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t } else { /* master channel */ err = get_cur_mix_value(cval, 0, &oval); - if (err < 0 && cval->chip->ignore_ctl_error) + if (err < 0 && cval->mixer->ignore_ctl_error) return 0; if (err < 0) return err; @@ -795,8 +808,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return; } - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->control = control; cval->cmask = ctl_mask; @@ -880,7 +892,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); - add_control_to_empty(state->chip->card, kctl); + add_control_to_empty(state, kctl); } @@ -963,8 +975,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, if (! cval) return; - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->control = in_ch + 1; /* based on 1 */ cval->val_type = USB_MIXER_S16; @@ -995,7 +1006,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - add_control_to_empty(state->chip->card, kctl); + add_control_to_empty(state, kctl); } @@ -1058,7 +1069,7 @@ static int mixer_ctl_procunit_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t int err, val; err = get_cur_ctl_value(cval, cval->control << 8, &val); - if (err < 0 && cval->chip->ignore_ctl_error) { + if (err < 0 && cval->mixer->ignore_ctl_error) { ucontrol->value.integer.value[0] = cval->min; return 0; } @@ -1077,7 +1088,7 @@ static int mixer_ctl_procunit_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t err = get_cur_ctl_value(cval, cval->control << 8, &oval); if (err < 0) { - if (cval->chip->ignore_ctl_error) + if (cval->mixer->ignore_ctl_error) return 0; return err; } @@ -1215,8 +1226,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; } - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->control = valinfo->control; cval->val_type = valinfo->val_type; @@ -1257,7 +1267,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - if ((err = add_control_to_empty(state->chip->card, kctl)) < 0) + if ((err = add_control_to_empty(state, kctl)) < 0) return err; } return 0; @@ -1305,7 +1315,7 @@ static int mixer_ctl_selector_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t err = get_cur_ctl_value(cval, 0, &val); if (err < 0) { - if (cval->chip->ignore_ctl_error) { + if (cval->mixer->ignore_ctl_error) { ucontrol->value.enumerated.item[0] = 0; return 0; } @@ -1324,7 +1334,7 @@ static int mixer_ctl_selector_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t err = get_cur_ctl_value(cval, 0, &oval); if (err < 0) { - if (cval->chip->ignore_ctl_error) + if (cval->mixer->ignore_ctl_error) return 0; return err; } @@ -1402,8 +1412,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; } - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->val_type = USB_MIXER_U8; cval->channels = 1; @@ -1468,7 +1477,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", cval->id, kctl->id.name, num_ins); - if ((err = add_control_to_empty(state->chip->card, kctl)) < 0) + if ((err = add_control_to_empty(state, kctl)) < 0) return err; return 0; @@ -1511,27 +1520,38 @@ static int parse_audio_unit(mixer_build_t *state, int unitid) } } +static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) +{ + kfree(mixer); +} + +static int snd_usb_mixer_dev_free(snd_device_t *device) +{ + struct usb_mixer_interface *mixer = device->device_data; + snd_usb_mixer_free(mixer); + return 0; +} + /* * create mixer controls * * walk through all OUTPUT_TERMINAL descriptors to search for mixers */ -int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) +static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) { unsigned char *desc; mixer_build_t state; int err; const struct usbmix_ctl_map *map; - struct usb_device_descriptor *dev = &chip->dev->descriptor; - struct usb_host_interface *hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; - - strcpy(chip->card->mixername, "USB Mixer"); + struct usb_device_descriptor *dev = &mixer->chip->dev->descriptor; + struct usb_host_interface *hostif; + hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; memset(&state, 0, sizeof(state)); - state.chip = chip; + state.chip = mixer->chip; + state.mixer = mixer; state.buffer = hostif->extra; state.buflen = hostif->extralen; - state.ctrlif = ctrlif; state.vendor = le16_to_cpu(dev->idVendor); state.product = le16_to_cpu(dev->idProduct); @@ -1540,13 +1560,10 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) if (map->vendor == state.vendor && map->product == state.product) { state.map = map->map; state.selector_map = map->selector_map; - chip->ignore_ctl_error = map->ignore_ctl_error; + mixer->ignore_ctl_error = map->ignore_ctl_error; break; } } -#ifdef IGNORE_CTL_ERROR - chip->ignore_ctl_error = 1; -#endif desc = NULL; while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) { @@ -1562,3 +1579,40 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) } return 0; } + +int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) +{ + static snd_device_ops_t dev_ops = { + .dev_free = snd_usb_mixer_dev_free + }; + struct usb_mixer_interface *mixer; + int err; + + strcpy(chip->card->mixername, "USB Mixer"); + + mixer = kcalloc(1, sizeof(*mixer), GFP_KERNEL); + if (!mixer) + return -ENOMEM; + mixer->chip = chip; + mixer->ctrlif = ctrlif; +#ifdef IGNORE_CTL_ERROR + mixer->ignore_ctl_error = 1; +#endif + + if ((err = snd_usb_mixer_controls(mixer)) < 0) { + snd_usb_mixer_free(mixer); + return err; + } + + err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); + if (err < 0) { + snd_usb_mixer_free(mixer); + return err; + } + list_add(&mixer->list, &chip->mixer_list); + return 0; +} + +void snd_usb_mixer_disconnect(struct list_head *p) +{ +} -- cgit v0.10.2 From 6639b6c2367f884ca172b78d69f7da17bfab2e5e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 16:26:14 +0200 Subject: [ALSA] usb-audio - add mixer control notifications USB generic driver Add support for the optional status interrupt endpoint in audio control interfaces, and translate USB status notifications into ALSA mixer control notifications. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 7bbcceb..dd045ea 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -55,6 +55,8 @@ struct usb_mixer_interface { unsigned int ctrlif; struct list_head list; unsigned int ignore_ctl_error; + struct urb *urb; + usb_mixer_elem_info_t **id_elems; /* array[256], indexed by unit id */ }; @@ -83,13 +85,15 @@ struct usb_mixer_build { struct usb_mixer_elem_info { struct usb_mixer_interface *mixer; + usb_mixer_elem_info_t *next_id_elem; /* list of controls with same id */ + snd_ctl_elem_id_t *elem_id; unsigned int id; unsigned int control; /* CS or ICN (high byte) */ unsigned int cmask; /* channel mask bitmap: 0 = master */ int channels; int val_type; int min, max, res; - unsigned int initialized: 1; + u8 initialized; }; @@ -414,6 +418,7 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) { + usb_mixer_elem_info_t *cval = kctl->private_data; int err; while (snd_ctl_find_id(state->chip->card, &kctl->id)) @@ -421,8 +426,12 @@ static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); snd_ctl_free_one(kctl); + return err; } - return err; + cval->elem_id = &kctl->id; + cval->next_id_elem = state->mixer->id_elems[cval->id]; + state->mixer->id_elems[cval->id] = cval; + return 0; } @@ -1522,6 +1531,11 @@ static int parse_audio_unit(mixer_build_t *state, int unitid) static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) { + kfree(mixer->id_elems); + if (mixer->urb) { + kfree(mixer->urb->transfer_buffer); + usb_free_urb(mixer->urb); + } kfree(mixer); } @@ -1580,6 +1594,76 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) return 0; } +static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, + int unitid) +{ + usb_mixer_elem_info_t *info; + + for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + info->elem_id); +} + +static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) +{ + struct usb_mixer_interface *mixer = urb->context; + + if (urb->status == 0) { + u8 *buf = urb->transfer_buffer; + int i; + + for (i = urb->actual_length; i >= 2; buf += 2, i -= 2) { + snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n", + buf[0], buf[1]); + /* ignore any notifications not from the control interface */ + if ((buf[0] & 0x0f) != 0) + continue; + if (!(buf[0] & 0x40)) + snd_usb_mixer_notify_id(mixer, buf[1]); + } + } + if (urb->status != -ENOENT && urb->status != -ECONNRESET) { + urb->dev = mixer->chip->dev; + usb_submit_urb(urb, GFP_ATOMIC); + } +} + +/* create the handler for the optional status interrupt endpoint */ +static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) +{ + struct usb_host_interface *hostif; + struct usb_endpoint_descriptor *ep; + void *transfer_buffer; + int buffer_length; + unsigned int epnum; + + hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; + /* we need one interrupt input endpoint */ + if (get_iface_desc(hostif)->bNumEndpoints < 1) + return 0; + ep = get_endpoint(hostif, 0); + if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN || + (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + return 0; + + epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + buffer_length = le16_to_cpu(ep->wMaxPacketSize); + transfer_buffer = kmalloc(buffer_length, GFP_KERNEL); + if (!transfer_buffer) + return -ENOMEM; + mixer->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!mixer->urb) { + kfree(transfer_buffer); + return -ENOMEM; + } + usb_fill_int_urb(mixer->urb, mixer->chip->dev, + usb_rcvintpipe(mixer->chip->dev, epnum), + transfer_buffer, buffer_length, + snd_usb_mixer_status_complete, mixer, ep->bInterval); + usb_submit_urb(mixer->urb, GFP_KERNEL); + return 0; +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1598,8 +1682,14 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) #ifdef IGNORE_CTL_ERROR mixer->ignore_ctl_error = 1; #endif + mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL); + if (!mixer->id_elems) { + kfree(mixer); + return -ENOMEM; + } - if ((err = snd_usb_mixer_controls(mixer)) < 0) { + if ((err = snd_usb_mixer_controls(mixer)) < 0 || + (err = snd_usb_mixer_status_create(mixer)) < 0) { snd_usb_mixer_free(mixer); return err; } @@ -1615,4 +1705,9 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) void snd_usb_mixer_disconnect(struct list_head *p) { + struct usb_mixer_interface *mixer; + + mixer = list_entry(p, struct usb_mixer_interface, list); + if (mixer->urb) + usb_kill_urb(mixer->urb); } -- cgit v0.10.2 From b259b10c420a59a2fdbcf5a3498253ebcbdffa1e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 16:29:28 +0200 Subject: [ALSA] usb-audio - add Extigy/Audigy 2 NX remote control support ALSA Core,USB generic driver Add an hwdep interface that supports reading remote control data from Sound Blaster Extigy and Audigy 2 NX devices. Signed-off-by: Clemens Ladisch diff --git a/include/sound/asound.h b/include/sound/asound.h index 26db585..4321e92 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -113,9 +113,10 @@ enum sndrv_hwdep_iface { SNDRV_HWDEP_IFACE_BLUETOOTH, /* Bluetooth audio */ SNDRV_HWDEP_IFACE_USX2Y_PCM, /* Tascam US122, US224 & US428 rawusb pcm */ SNDRV_HWDEP_IFACE_PCXHR, /* Digigram PCXHR */ + SNDRV_HWDEP_IFACE_SB_RC, /* SB Extigy/Audigy2NX remote control */ /* Don't forget to change the following: */ - SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_PCXHR + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC }; struct sndrv_hwdep_info { diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index dd045ea..7ea42d4 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "usbaudio.h" @@ -57,6 +58,19 @@ struct usb_mixer_interface { unsigned int ignore_ctl_error; struct urb *urb; usb_mixer_elem_info_t **id_elems; /* array[256], indexed by unit id */ + + /* Sound Blaster remote control stuff */ + enum { + RC_NONE, + RC_EXTIGY, + RC_AUDIGY2NX, + } rc_type; + unsigned long rc_hwdep_open; + u32 rc_code; + wait_queue_head_t rc_waitq; + struct urb *rc_urb; + struct usb_ctrlrequest *rc_setup_packet; + u8 rc_buffer[6]; }; @@ -1536,6 +1550,9 @@ static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) kfree(mixer->urb->transfer_buffer); usb_free_urb(mixer->urb); } + if (mixer->rc_urb) + usb_free_urb(mixer->rc_urb); + kfree(mixer->rc_setup_packet); kfree(mixer); } @@ -1604,6 +1621,17 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, info->elem_id); } +static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, + int unitid) +{ + /* SB remote control */ + if (mixer->rc_type != RC_NONE && unitid == 0) { + /* read control code from device memory */ + mixer->rc_urb->dev = mixer->chip->dev; + usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); + } +} + static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) { struct usb_mixer_interface *mixer = urb->context; @@ -1620,6 +1648,8 @@ static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) continue; if (!(buf[0] & 0x40)) snd_usb_mixer_notify_id(mixer, buf[1]); + else + snd_usb_mixer_memory_change(mixer, buf[1]); } } if (urb->status != -ENOENT && urb->status != -ECONNRESET) { @@ -1664,6 +1694,126 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) return 0; } +static void snd_usb_soundblaster_remote_complete(struct urb *urb, + struct pt_regs *regs) +{ + struct usb_mixer_interface *mixer = urb->context; + /* + * format of remote control data: + * Extigy: xx 00 + * Audigy 2 NX: 06 80 xx 00 00 00 + */ + int offset = mixer->rc_type == RC_EXTIGY ? 0 : 2; + u32 code; + + if (urb->status < 0 || urb->actual_length <= offset) + return; + code = mixer->rc_buffer[offset]; + /* the Mute button actually changes the mixer control */ + if (code == 13) + snd_usb_mixer_notify_id(mixer, 18); + mixer->rc_code = code; + wmb(); + wake_up(&mixer->rc_waitq); +} + +static int snd_usb_sbrc_hwdep_open(snd_hwdep_t *hw, struct file *file) +{ + struct usb_mixer_interface *mixer = hw->private_data; + + if (test_and_set_bit(0, &mixer->rc_hwdep_open)) + return -EBUSY; + return 0; +} + +static int snd_usb_sbrc_hwdep_release(snd_hwdep_t *hw, struct file *file) +{ + struct usb_mixer_interface *mixer = hw->private_data; + + clear_bit(0, &mixer->rc_hwdep_open); + smp_mb__after_clear_bit(); + return 0; +} + +static long snd_usb_sbrc_hwdep_read(snd_hwdep_t *hw, char __user *buf, + long count, loff_t *offset) +{ + struct usb_mixer_interface *mixer = hw->private_data; + int err; + u32 rc_code; + + if (count != 1) + return -EINVAL; + err = wait_event_interruptible(mixer->rc_waitq, + (rc_code = xchg(&mixer->rc_code, 0)) != 0); + if (err == 0) { + err = put_user(rc_code, buf); + } + return err < 0 ? err : count; +} + +static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file, + poll_table *wait) +{ + struct usb_mixer_interface *mixer = hw->private_data; + + poll_wait(file, &mixer->rc_waitq, wait); + return mixer->rc_code ? POLLIN | POLLRDNORM : 0; +} + +static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) +{ + snd_hwdep_t *hwdep; + int err, len; + + switch (le16_to_cpu(mixer->chip->dev->descriptor.idProduct)) { + case 0x3000: + mixer->rc_type = RC_EXTIGY; + len = 2; + break; + case 0x3020: + mixer->rc_type = RC_AUDIGY2NX; + len = 6; + break; + default: + return 0; + } + + init_waitqueue_head(&mixer->rc_waitq); + err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); + if (err < 0) + return err; + snprintf(hwdep->name, sizeof(hwdep->name), + "%s remote control", mixer->chip->card->shortname); + hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; + hwdep->private_data = mixer; + hwdep->ops.read = snd_usb_sbrc_hwdep_read; + hwdep->ops.open = snd_usb_sbrc_hwdep_open; + hwdep->ops.release = snd_usb_sbrc_hwdep_release; + hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; + + mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!mixer->rc_urb) + return -ENOMEM; + mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL); + if (!mixer->rc_setup_packet) { + usb_free_urb(mixer->rc_urb); + mixer->rc_urb = NULL; + return -ENOMEM; + } + mixer->rc_setup_packet->bRequestType = + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + mixer->rc_setup_packet->bRequest = GET_MEM; + mixer->rc_setup_packet->wValue = cpu_to_le16(0); + mixer->rc_setup_packet->wIndex = cpu_to_le16(0); + mixer->rc_setup_packet->wLength = cpu_to_le16(len); + usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, + usb_rcvctrlpipe(mixer->chip->dev, 0), + (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, + snd_usb_soundblaster_remote_complete, mixer); + return 0; +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1694,6 +1844,13 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) return err; } + if (le16_to_cpu(chip->dev->descriptor.idVendor) == 0x041e) { + if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { + snd_usb_mixer_free(mixer); + return err; + } + } + err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); if (err < 0) { snd_usb_mixer_free(mixer); @@ -1710,4 +1867,6 @@ void snd_usb_mixer_disconnect(struct list_head *p) mixer = list_entry(p, struct usb_mixer_interface, list); if (mixer->urb) usb_kill_urb(mixer->urb); + if (mixer->rc_urb) + usb_kill_urb(mixer->rc_urb); } -- cgit v0.10.2 From 27d10f5664c7650af3b2ffadfefaf19b36dc7bd8 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:51:26 +0200 Subject: [ALSA] usb-audio - cache vendor/product IDs USB generic driver Cache the decoded values of idVendor/idProduct to get rid of most of those ugly le16_to_cpu() calls. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index eeb09bb..e759b73 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2184,17 +2184,15 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor /* * check if the device uses big-endian samples */ -static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) +static int is_big_endian_format(snd_usb_audio_t *chip, struct audioformat *fp) { - /* M-Audio */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763) { - /* Quattro: captured data only */ - if (le16_to_cpu(dev->descriptor.idProduct) == 0x2001 && - fp->endpoint & USB_DIR_IN) - return 1; - /* Audiophile USB */ - if (le16_to_cpu(dev->descriptor.idProduct) == 0x2003) + switch (chip->usb_id) { + case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */ + if (fp->endpoint & USB_DIR_IN) return 1; + break; + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ + return 1; } return 0; } @@ -2208,7 +2206,7 @@ static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) * @format: the format tag (wFormatTag) * @fmt: the format type descriptor */ -static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_i_type(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt) { int pcm_format; @@ -2221,12 +2219,12 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat switch (format) { case 0: /* some devices don't define this correctly... */ snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", - dev->devnum, fp->iface, fp->altsetting); + chip->dev->devnum, fp->iface, fp->altsetting); /* fall-through */ case USB_AUDIO_FORMAT_PCM: if (sample_width > sample_bytes * 8) { snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", - dev->devnum, fp->iface, fp->altsetting, + chip->dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes); } /* check the format byte size */ @@ -2235,13 +2233,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat pcm_format = SNDRV_PCM_FORMAT_S8; break; case 2: - if (is_big_endian_format(dev, fp)) + if (is_big_endian_format(chip, fp)) pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ else pcm_format = SNDRV_PCM_FORMAT_S16_LE; break; case 3: - if (is_big_endian_format(dev, fp)) + if (is_big_endian_format(chip, fp)) pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ else pcm_format = SNDRV_PCM_FORMAT_S24_3LE; @@ -2251,14 +2249,14 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat break; default: snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", - dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes); + chip->dev->devnum, fp->iface, + fp->altsetting, sample_width, sample_bytes); break; } break; case USB_AUDIO_FORMAT_PCM8: /* Dallas DS4201 workaround */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa && - le16_to_cpu(dev->descriptor.idProduct) == 0x4201) + if (chip->usb_id == USB_ID(0x04fa, 0x4201)) pcm_format = SNDRV_PCM_FORMAT_S8; else pcm_format = SNDRV_PCM_FORMAT_U8; @@ -2274,7 +2272,7 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat break; default: snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n", - dev->devnum, fp->iface, fp->altsetting, format); + chip->dev->devnum, fp->iface, fp->altsetting, format); break; } return pcm_format; @@ -2291,13 +2289,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat * @offset: the start offset of descriptor pointing the rate type * (7 for type I and II, 8 for type II) */ -static int parse_audio_format_rates(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_rates(snd_usb_audio_t *chip, struct audioformat *fp, unsigned char *fmt, int offset) { int nr_rates = fmt[offset]; if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", - dev->devnum, fp->iface, fp->altsetting); + chip->dev->devnum, fp->iface, fp->altsetting); return -1; } @@ -2344,7 +2342,7 @@ static int parse_audio_format_rates(struct usb_device *dev, struct audioformat * /* * parse the format type I and III descriptors */ -static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_i(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt) { int pcm_format; @@ -2356,7 +2354,7 @@ static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, */ pcm_format = SNDRV_PCM_FORMAT_S16_LE; } else { - pcm_format = parse_audio_format_i_type(dev, fp, format, fmt); + pcm_format = parse_audio_format_i_type(chip, fp, format, fmt); if (pcm_format < 0) return -1; } @@ -2364,16 +2362,16 @@ static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, fp->channels = fmt[4]; if (fp->channels < 1) { snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", - dev->devnum, fp->iface, fp->altsetting, fp->channels); + chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); return -1; } - return parse_audio_format_rates(dev, fp, fmt, 7); + return parse_audio_format_rates(chip, fp, fmt, 7); } /* * prase the format type II descriptor */ -static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_ii(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt) { int brate, framesize; @@ -2388,7 +2386,7 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, break; default: snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected. processed as MPEG.\n", - dev->devnum, fp->iface, fp->altsetting, format); + chip->dev->devnum, fp->iface, fp->altsetting, format); fp->format = SNDRV_PCM_FORMAT_MPEG; break; } @@ -2397,10 +2395,10 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */ snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); fp->frame_size = framesize; - return parse_audio_format_rates(dev, fp, fmt, 8); /* fmt[8..] sample rates */ + return parse_audio_format_rates(chip, fp, fmt, 8); /* fmt[8..] sample rates */ } -static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt, int stream) { int err; @@ -2408,14 +2406,14 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, switch (fmt[3]) { case USB_FORMAT_TYPE_I: case USB_FORMAT_TYPE_III: - err = parse_audio_format_i(dev, fp, format, fmt); + err = parse_audio_format_i(chip, fp, format, fmt); break; case USB_FORMAT_TYPE_II: - err = parse_audio_format_ii(dev, fp, format, fmt); + err = parse_audio_format_ii(chip, fp, format, fmt); break; default: snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", - dev->devnum, fp->iface, fp->altsetting, fmt[3]); + chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]); return -1; } fp->fmt_type = fmt[3]; @@ -2426,9 +2424,8 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, /* extigy apparently supports sample rates other than 48k * but not in ordinary way. so we enable only 48k atm. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - (le16_to_cpu(dev->descriptor.idProduct) == 0x3000 || - le16_to_cpu(dev->descriptor.idProduct) == 0x3020)) { + if (chip->usb_id == USB_ID(0x041e, 0x3000) || + chip->usb_id == USB_ID(0x041e, 0x3020)) { if (fmt[3] == USB_FORMAT_TYPE_I && stream == SNDRV_PCM_STREAM_PLAYBACK && fp->rates != SNDRV_PCM_RATE_48000 && @@ -2532,8 +2529,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) /* some quirks for attributes here */ /* workaround for AudioTrak Optoplay */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0a92 && - le16_to_cpu(dev->descriptor.idProduct) == 0x0053) { + if (chip->usb_id == USB_ID(0x0a92, 0x0053)) { /* Optoplay sets the sample rate attribute although * it seems not supporting it in fact. */ @@ -2541,8 +2537,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) } /* workaround for M-Audio Audiophile USB */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763 && - le16_to_cpu(dev->descriptor.idProduct) == 0x2003) { + if (chip->usb_id == USB_ID(0x0763, 0x2003)) { /* doesn't set the sample rate attribute, but supports it */ fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; } @@ -2551,11 +2546,9 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) * plantronics headset and Griffin iMic have set adaptive-in * although it's really not... */ - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x047f && - le16_to_cpu(dev->descriptor.idProduct) == 0x0ca1) || + if (chip->usb_id == USB_ID(0x047f, 0x0ca1) || /* Griffin iMic (note that there is an older model 77d:223) */ - (le16_to_cpu(dev->descriptor.idVendor) == 0x077d && - le16_to_cpu(dev->descriptor.idProduct) == 0x07af)) { + chip->usb_id == USB_ID(0x077d, 0x07af)) { fp->ep_attr &= ~EP_ATTR_MASK; if (stream == SNDRV_PCM_STREAM_PLAYBACK) fp->ep_attr |= EP_ATTR_ADAPTIVE; @@ -2564,7 +2557,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) } /* ok, let's parse further... */ - if (parse_audio_format(dev, fp, format, fmt, stream) < 0) { + if (parse_audio_format(chip, fp, format, fmt, stream) < 0) { kfree(fp->rate_table); kfree(fp); continue; @@ -2799,7 +2792,7 @@ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &ua25_ep }; - if (le16_to_cpu(chip->dev->descriptor.idProduct) == 0x002b) + if (chip->usb_id == USB_ID(0x0582, 0x002b)) return snd_usb_create_midi_interface(chip, iface, &ua700_quirk); else @@ -3018,8 +3011,8 @@ static void proc_audio_usbid_read(snd_info_entry_t *entry, snd_info_buffer_t *bu snd_usb_audio_t *chip = entry->private_data; if (! chip->shutdown) snd_iprintf(buffer, "%04x:%04x\n", - le16_to_cpu(chip->dev->descriptor.idVendor), - le16_to_cpu(chip->dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), + USB_ID_PRODUCT(chip->usb_id)); } static void snd_usb_audio_create_proc(snd_usb_audio_t *chip) @@ -3089,6 +3082,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, chip->index = idx; chip->dev = dev; chip->card = card; + chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->midi_list); INIT_LIST_HEAD(&chip->mixer_list); @@ -3101,8 +3096,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, strcpy(card->driver, "USB-Audio"); sprintf(component, "USB%04x:%04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); snd_component_add(card, component); /* retrieve the device string as shortname */ @@ -3114,8 +3108,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, card->shortname, sizeof(card->shortname)) <= 0) { /* no name available from anywhere, so use ID */ sprintf(card->shortname, "USB Device %#04x:%#04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), + USB_ID_PRODUCT(chip->usb_id)); } } @@ -3173,17 +3167,19 @@ static void *snd_usb_audio_probe(struct usb_device *dev, snd_usb_audio_t *chip; struct usb_host_interface *alts; int ifnum; + u32 id; alts = &intf->altsetting[0]; ifnum = get_iface_desc(alts)->bInterfaceNumber; + id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) goto __err_val; /* SB Extigy needs special boot-up sequence */ /* if more models come, this will go to the quirk list. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - le16_to_cpu(dev->descriptor.idProduct) == 0x3000) { + if (id == USB_ID(0x041e, 0x3000)) { if (snd_usb_extigy_boot_quirk(dev, intf) < 0) goto __err_val; config = dev->actconfig; @@ -3217,8 +3213,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev, } for (i = 0; i < SNDRV_CARDS; i++) if (enable[i] && ! usb_chip[i] && - (vid[i] == -1 || vid[i] == le16_to_cpu(dev->descriptor.idVendor)) && - (pid[i] == -1 || pid[i] == le16_to_cpu(dev->descriptor.idProduct))) { + (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && + (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { goto __error; } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 41d842d..aedb42a 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -118,6 +118,11 @@ /* maximum number of endpoints per interface */ #define MIDI_MAX_ENDPOINTS 2 +/* handling of USB vendor/product ID pairs as 32-bit numbers */ +#define USB_ID(vendor, product) (((vendor) << 16) | (product)) +#define USB_ID_VENDOR(id) ((id) >> 16) +#define USB_ID_PRODUCT(id) ((u16)(id)) + /* */ @@ -127,6 +132,7 @@ struct snd_usb_audio { int index; struct usb_device *dev; snd_card_t *card; + u32 usb_id; int shutdown; int num_interfaces; diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 304a134..bee7006 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -955,88 +955,87 @@ static snd_rawmidi_substream_t* snd_usbmidi_find_substream(snd_usb_midi_t* umidi * such as internal control or synthesizer ports. */ static struct { - __u16 vendor; - __u16 product; + u32 id; int port; const char *name_format; } snd_usbmidi_port_names[] = { /* Roland UA-100 */ - {0x0582, 0x0000, 2, "%s Control"}, + { USB_ID(0x0582, 0x0000), 2, "%s Control" }, /* Roland SC-8850 */ - {0x0582, 0x0003, 0, "%s Part A"}, - {0x0582, 0x0003, 1, "%s Part B"}, - {0x0582, 0x0003, 2, "%s Part C"}, - {0x0582, 0x0003, 3, "%s Part D"}, - {0x0582, 0x0003, 4, "%s MIDI 1"}, - {0x0582, 0x0003, 5, "%s MIDI 2"}, + { USB_ID(0x0582, 0x0003), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0003), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0003), 2, "%s Part C" }, + { USB_ID(0x0582, 0x0003), 3, "%s Part D" }, + { USB_ID(0x0582, 0x0003), 4, "%s MIDI 1" }, + { USB_ID(0x0582, 0x0003), 5, "%s MIDI 2" }, /* Roland U-8 */ - {0x0582, 0x0004, 0, "%s MIDI"}, - {0x0582, 0x0004, 1, "%s Control"}, + { USB_ID(0x0582, 0x0004), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0004), 1, "%s Control" }, /* Roland SC-8820 */ - {0x0582, 0x0007, 0, "%s Part A"}, - {0x0582, 0x0007, 1, "%s Part B"}, - {0x0582, 0x0007, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x0007), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0007), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0007), 2, "%s MIDI" }, /* Roland SK-500 */ - {0x0582, 0x000b, 0, "%s Part A"}, - {0x0582, 0x000b, 1, "%s Part B"}, - {0x0582, 0x000b, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x000b), 0, "%s Part A" }, + { USB_ID(0x0582, 0x000b), 1, "%s Part B" }, + { USB_ID(0x0582, 0x000b), 2, "%s MIDI" }, /* Roland SC-D70 */ - {0x0582, 0x000c, 0, "%s Part A"}, - {0x0582, 0x000c, 1, "%s Part B"}, - {0x0582, 0x000c, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x000c), 0, "%s Part A" }, + { USB_ID(0x0582, 0x000c), 1, "%s Part B" }, + { USB_ID(0x0582, 0x000c), 2, "%s MIDI" }, /* Edirol UM-880 */ - {0x0582, 0x0014, 8, "%s Control"}, + { USB_ID(0x0582, 0x0014), 8, "%s Control" }, /* Edirol SD-90 */ - {0x0582, 0x0016, 0, "%s Part A"}, - {0x0582, 0x0016, 1, "%s Part B"}, - {0x0582, 0x0016, 2, "%s MIDI 1"}, - {0x0582, 0x0016, 3, "%s MIDI 2"}, + { USB_ID(0x0582, 0x0016), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0016), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0016), 2, "%s MIDI 1" }, + { USB_ID(0x0582, 0x0016), 3, "%s MIDI 2" }, /* Edirol UM-550 */ - {0x0582, 0x0023, 5, "%s Control"}, + { USB_ID(0x0582, 0x0023), 5, "%s Control" }, /* Edirol SD-20 */ - {0x0582, 0x0027, 0, "%s Part A"}, - {0x0582, 0x0027, 1, "%s Part B"}, - {0x0582, 0x0027, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x0027), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0027), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0027), 2, "%s MIDI" }, /* Edirol SD-80 */ - {0x0582, 0x0029, 0, "%s Part A"}, - {0x0582, 0x0029, 1, "%s Part B"}, - {0x0582, 0x0029, 2, "%s MIDI 1"}, - {0x0582, 0x0029, 3, "%s MIDI 2"}, + { USB_ID(0x0582, 0x0029), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0029), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0029), 2, "%s MIDI 1" }, + { USB_ID(0x0582, 0x0029), 3, "%s MIDI 2" }, /* Edirol UA-700 */ - {0x0582, 0x002b, 0, "%s MIDI"}, - {0x0582, 0x002b, 1, "%s Control"}, + { USB_ID(0x0582, 0x002b), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x002b), 1, "%s Control" }, /* Roland VariOS */ - {0x0582, 0x002f, 0, "%s MIDI"}, - {0x0582, 0x002f, 1, "%s External MIDI"}, - {0x0582, 0x002f, 2, "%s Sync"}, + { USB_ID(0x0582, 0x002f), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x002f), 1, "%s External MIDI" }, + { USB_ID(0x0582, 0x002f), 2, "%s Sync" }, /* Edirol PCR */ - {0x0582, 0x0033, 0, "%s MIDI"}, - {0x0582, 0x0033, 1, "%s 1"}, - {0x0582, 0x0033, 2, "%s 2"}, + { USB_ID(0x0582, 0x0033), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0033), 1, "%s 1" }, + { USB_ID(0x0582, 0x0033), 2, "%s 2" }, /* BOSS GS-10 */ - {0x0582, 0x003b, 0, "%s MIDI"}, - {0x0582, 0x003b, 1, "%s Control"}, + { USB_ID(0x0582, 0x003b), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x003b), 1, "%s Control" }, /* Edirol UA-1000 */ - {0x0582, 0x0044, 0, "%s MIDI"}, - {0x0582, 0x0044, 1, "%s Control"}, + { USB_ID(0x0582, 0x0044), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0044), 1, "%s Control" }, /* Edirol UR-80 */ - {0x0582, 0x0048, 0, "%s MIDI"}, - {0x0582, 0x0048, 1, "%s 1"}, - {0x0582, 0x0048, 2, "%s 2"}, + { USB_ID(0x0582, 0x0048), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0048), 1, "%s 1" }, + { USB_ID(0x0582, 0x0048), 2, "%s 2" }, /* Edirol PCR-A */ - {0x0582, 0x004d, 0, "%s MIDI"}, - {0x0582, 0x004d, 1, "%s 1"}, - {0x0582, 0x004d, 2, "%s 2"}, + { USB_ID(0x0582, 0x004d), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x004d), 1, "%s 1" }, + { USB_ID(0x0582, 0x004d), 2, "%s 2" }, /* M-Audio MidiSport 8x8 */ - {0x0763, 0x1031, 8, "%s Control"}, - {0x0763, 0x1033, 8, "%s Control"}, + { USB_ID(0x0763, 0x1031), 8, "%s Control" }, + { USB_ID(0x0763, 0x1033), 8, "%s Control" }, /* MOTU Fastlane */ - {0x07fd, 0x0001, 0, "%s MIDI A"}, - {0x07fd, 0x0001, 1, "%s MIDI B"}, + { USB_ID(0x07fd, 0x0001), 0, "%s MIDI A" }, + { USB_ID(0x07fd, 0x0001), 1, "%s MIDI B" }, /* Emagic Unitor8/AMT8/MT4 */ - {0x086a, 0x0001, 8, "%s Broadcast"}, - {0x086a, 0x0002, 8, "%s Broadcast"}, - {0x086a, 0x0003, 4, "%s Broadcast"}, + { USB_ID(0x086a, 0x0001), 8, "%s Broadcast" }, + { USB_ID(0x086a, 0x0002), 8, "%s Broadcast" }, + { USB_ID(0x086a, 0x0003), 4, "%s Broadcast" }, }; static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, @@ -1044,7 +1043,6 @@ static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, snd_rawmidi_substream_t** rsubstream) { int i; - __u16 vendor, product; const char *name_format; snd_rawmidi_substream_t* substream = snd_usbmidi_find_substream(umidi, stream, number); @@ -1055,11 +1053,8 @@ static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, /* TODO: read port name from jack descriptor */ name_format = "%s MIDI %d"; - vendor = le16_to_cpu(umidi->chip->dev->descriptor.idVendor); - product = le16_to_cpu(umidi->chip->dev->descriptor.idProduct); for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) { - if (snd_usbmidi_port_names[i].vendor == vendor && - snd_usbmidi_port_names[i].product == product && + if (snd_usbmidi_port_names[i].id == umidi->chip->usb_id && snd_usbmidi_port_names[i].port == number) { name_format = snd_usbmidi_port_names[i].name_format; break; @@ -1226,7 +1221,7 @@ static int snd_usbmidi_detect_endpoints(snd_usb_midi_t* umidi, struct usb_endpoint_descriptor* epd; int i, out_eps = 0, in_eps = 0; - if (le16_to_cpu(umidi->chip->dev->descriptor.idVendor) == 0x0582) + if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); if (endpoint[0].out_ep || endpoint[0].in_ep) diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 7ea42d4..bfaec4f 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -89,8 +89,6 @@ struct usb_mixer_build { struct usb_mixer_interface *mixer; unsigned char *buffer; unsigned int buflen; - unsigned short vendor; - unsigned short product; DECLARE_BITMAP(unitbitmap, 256); usb_audio_term_t oterm; const struct usbmix_name_map *map; @@ -906,11 +904,16 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, /* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */ /* is not very clear from datasheets */ /* I hope that the min value is -15360 for newer firmware --jk */ - if (((state->vendor == 0x471 && (state->product == 0x104 || state->product == 0x105 || state->product == 0x101)) || - (state->vendor == 0x672 && state->product == 0x1041)) && !strcmp(kctl->id.name, "PCM Playback Volume") && - cval->min == -15616) { - snd_printk("USB Audio: using volume control quirk for the UDA1321/N101 chip\n"); - cval->max = -256; + switch (state->chip->usb_id) { + case USB_ID(0x0471, 0x0101): + case USB_ID(0x0471, 0x0104): + case USB_ID(0x0471, 0x0105): + case USB_ID(0x0672, 0x1041): + if (!strcmp(kctl->id.name, "PCM Playback Volume") && + cval->min == -15616) { + snd_printk("using volume control quirk for the UDA1321/N101 chip\n"); + cval->max = -256; + } } snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", @@ -1574,7 +1577,6 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) mixer_build_t state; int err; const struct usbmix_ctl_map *map; - struct usb_device_descriptor *dev = &mixer->chip->dev->descriptor; struct usb_host_interface *hostif; hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; @@ -1583,12 +1585,10 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) state.mixer = mixer; state.buffer = hostif->extra; state.buflen = hostif->extralen; - state.vendor = le16_to_cpu(dev->idVendor); - state.product = le16_to_cpu(dev->idProduct); /* check the mapping table */ - for (map = usbmix_ctl_maps; map->vendor; map++) { - if (map->vendor == state.vendor && map->product == state.product) { + for (map = usbmix_ctl_maps; map->id; map++) { + if (map->id == state.chip->usb_id) { state.map = map->map; state.selector_map = map->selector_map; mixer->ignore_ctl_error = map->ignore_ctl_error; @@ -1766,12 +1766,12 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) snd_hwdep_t *hwdep; int err, len; - switch (le16_to_cpu(mixer->chip->dev->descriptor.idProduct)) { - case 0x3000: + switch (mixer->chip->usb_id) { + case USB_ID(0x041e, 0x3000): mixer->rc_type = RC_EXTIGY; len = 2; break; - case 0x3020: + case USB_ID(0x041e, 0x3020): mixer->rc_type = RC_AUDIGY2NX; len = 6; break; @@ -1844,11 +1844,9 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) return err; } - if (le16_to_cpu(chip->dev->descriptor.idVendor) == 0x041e) { - if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { - snd_usb_mixer_free(mixer); - return err; - } + if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { + snd_usb_mixer_free(mixer); + return err; } err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index adb0abb..f05500b 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -33,8 +33,7 @@ struct usbmix_selector_map { }; struct usbmix_ctl_map { - int vendor; - int product; + u32 id; const struct usbmix_name_map *map; const struct usbmix_selector_map *selector_map; int ignore_ctl_error; @@ -225,26 +224,26 @@ static struct usbmix_name_map justlink_map[] = { static struct usbmix_ctl_map usbmix_ctl_maps[] = { { - .vendor = 0x41e, .product = 0x3000, + .id = USB_ID(0x041e, 0x3000), .map = extigy_map, .ignore_ctl_error = 1, }, { - .vendor = 0x41e, .product = 0x3010, + .id = USB_ID(0x041e, 0x3010), .map = mp3plus_map, }, { - .vendor = 0x41e, .product = 0x3020, + .id = USB_ID(0x041e, 0x3020), .map = audigy2nx_map, .selector_map = audigy2nx_selectors, }, { - .vendor = 0x8bb, .product = 0x2702, + .id = USB_ID(0x08bb, 0x2702), .map = linex_map, .ignore_ctl_error = 1, }, { - .vendor = 0xc45, .product = 0x1158, + .id = USB_ID(0x0c45, 0x1158), .map = justlink_map, }, { 0 } /* terminator */ -- cgit v0.10.2 From 4dc40a3cc4778ebcb6212bdb71b48690a153be07 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:52:32 +0200 Subject: [ALSA] usb-audio - allow type 0 extension units USB generic driver Extension units can have type 0, so do not ignore them when constructing mixer controls. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index bfaec4f..5683ae0 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -1232,9 +1232,6 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char } type = combine_word(&dsc[4]); - if (! type) - return 0; /* undefined? */ - for (info = list; info && info->type; info++) if (info->type == type) break; -- cgit v0.10.2 From 1149a64fe4916fe6fdc8938043a0dc9a6551ab63 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:53:46 +0200 Subject: [ALSA] usb-audio - use proper interval between synchronization packets USB generic driver Add sanity checks when reading the bRefresh value, and actually use it for the synchronization packets instead of polling at 1000 Hz. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index e759b73..e1a648d 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1051,10 +1051,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by u->urb->pipe = subs->syncpipe; u->urb->transfer_flags = URB_ISO_ASAP; u->urb->number_of_packets = u->packets; - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) - u->urb->interval = 8; - else - u->urb->interval = 1; + u->urb->interval = 1 << subs->syncinterval; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); } @@ -1272,7 +1269,12 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) subs->syncpipe = usb_rcvisocpipe(dev, ep); else subs->syncpipe = usb_sndisocpipe(dev, ep); - subs->syncinterval = get_endpoint(alts, 1)->bRefresh; + if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && + get_endpoint(alts, 1)->bRefresh >= 1 && + get_endpoint(alts, 1)->bRefresh <= 9) + subs->syncinterval = get_endpoint(alts, 1)->bRefresh; + else + subs->syncinterval = 1; } /* always fill max packet size */ -- cgit v0.10.2 From ca81090a00e3e7152fe1f3d7398f11d57919428e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:55:54 +0200 Subject: [ALSA] usb-audio - use only one packet in synchronization feedback URBs USB generic driver Do not use more than one packet in synchronization feedback URBs because it would be pointless to send or receive more than one value at the same time. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index e1a648d..a5e97d0 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -177,7 +177,7 @@ struct snd_usb_substream { unsigned int nurbs; /* # urbs */ snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */ - char syncbuf[SYNC_URBS * MAX_PACKS * 4]; /* sync buffer; it's so small - let's get static */ + char syncbuf[SYNC_URBS * 4]; /* sync buffer; it's so small - let's get static */ char *tmpbuf; /* temporary buffer for playback */ u64 formats; /* format bitmasks (all or'ed) */ @@ -251,17 +251,13 @@ static int prepare_capture_sync_urb(snd_usb_substream_t *subs, { unsigned char *cp = urb->transfer_buffer; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - int i, offs; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) { - urb->iso_frame_desc[i].length = 3; - urb->iso_frame_desc[i].offset = offs; - cp[0] = subs->freqn >> 2; - cp[1] = subs->freqn >> 10; - cp[2] = subs->freqn >> 18; - } + urb->iso_frame_desc[0].length = 3; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn >> 2; + cp[1] = subs->freqn >> 10; + cp[2] = subs->freqn >> 18; return 0; } @@ -277,18 +273,14 @@ static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs, { unsigned char *cp = urb->transfer_buffer; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - int i, offs; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) { - urb->iso_frame_desc[i].length = 4; - urb->iso_frame_desc[i].offset = offs; - cp[0] = subs->freqn; - cp[1] = subs->freqn >> 8; - cp[2] = subs->freqn >> 16; - cp[3] = subs->freqn >> 24; - } + urb->iso_frame_desc[0].length = 4; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn; + cp[1] = subs->freqn >> 8; + cp[2] = subs->freqn >> 16; + cp[3] = subs->freqn >> 24; return 0; } @@ -418,15 +410,11 @@ static int prepare_playback_sync_urb(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i, offs; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) { - urb->iso_frame_desc[i].length = 3; - urb->iso_frame_desc[i].offset = offs; - } + urb->iso_frame_desc[0].length = 3; + urb->iso_frame_desc[0].offset = 0; return 0; } @@ -440,15 +428,11 @@ static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i, offs; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) { - urb->iso_frame_desc[i].length = 4; - urb->iso_frame_desc[i].offset = offs; - } + urb->iso_frame_desc[0].length = 4; + urb->iso_frame_desc[0].offset = 0; return 0; } @@ -462,17 +446,12 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i; - unsigned int f, found; - unsigned char *cp = urb->transfer_buffer; + unsigned int f; unsigned long flags; - found = 0; - for (i = 0; i < urb->number_of_packets; i++, cp += 4) { - if (urb->iso_frame_desc[i].status || - urb->iso_frame_desc[i].actual_length < 3) - continue; - f = combine_triple(cp) << 2; + if (urb->iso_frame_desc[0].status == 0 && + urb->iso_frame_desc[0].actual_length == 3) { + f = combine_triple((u8*)urb->transfer_buffer) << 2; #if 0 if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) { snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n", @@ -481,11 +460,8 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, continue; } #endif - found = f; - } - if (found) { spin_lock_irqsave(&subs->lock, flags); - subs->freqm = found; + subs->freqm = f; spin_unlock_irqrestore(&subs->lock, flags); } @@ -502,21 +478,14 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i; - unsigned int found; - unsigned char *cp = urb->transfer_buffer; + unsigned int f; unsigned long flags; - found = 0; - for (i = 0; i < urb->number_of_packets; i++, cp += 4) { - if (urb->iso_frame_desc[i].status || - urb->iso_frame_desc[i].actual_length < 4) - continue; - found = combine_quad(cp) & 0x0fffffff; - } - if (found) { + if (urb->iso_frame_desc[0].status == 0 && + urb->iso_frame_desc[0].actual_length == 4) { + f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; spin_lock_irqsave(&subs->lock, flags); - subs->freqm = found; + subs->freqm = f; spin_unlock_irqrestore(&subs->lock, flags); } @@ -1039,18 +1008,18 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by snd_urb_ctx_t *u = &subs->syncurb[i]; u->index = i; u->subs = subs; - u->packets = nrpacks; - u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); + u->packets = 1; + u->urb = usb_alloc_urb(1, GFP_KERNEL); if (! u->urb) { release_substream_urbs(subs, 0); return -ENOMEM; } - u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4; - u->urb->transfer_buffer_length = nrpacks * 4; + u->urb->transfer_buffer = subs->syncbuf + i * 4; + u->urb->transfer_buffer_length = 4; u->urb->dev = subs->dev; u->urb->pipe = subs->syncpipe; u->urb->transfer_flags = URB_ISO_ASAP; - u->urb->number_of_packets = u->packets; + u->urb->number_of_packets = 1; u->urb->interval = 1 << subs->syncinterval; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); -- cgit v0.10.2 From 434b7f56872fc5783c77f362e895da8e22168325 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:58:31 +0200 Subject: [ALSA] usb-audio - make SB remote control device LIRC compatible USB generic driver Add ioctls to the Sound Blaster remote control hwdep device so that it can be used with LIRC. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 5683ae0..d90d6fa 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -39,6 +39,18 @@ #include "usbaudio.h" +#if 0 +#include +#else +/* only those symbols from lirc.h we actually need: */ +#include +#define LIRC_MODE2REC(x) ((x) << 16) +#define LIRC_MODE_CODE 0x00000008 +#define LIRC_CAN_REC_CODE LIRC_MODE2REC(LIRC_MODE_CODE) +#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) +#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) +#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) +#endif /* */ @@ -1739,12 +1751,15 @@ static long snd_usb_sbrc_hwdep_read(snd_hwdep_t *hw, char __user *buf, int err; u32 rc_code; - if (count != 1) + if (count != 1 && count != 4) return -EINVAL; err = wait_event_interruptible(mixer->rc_waitq, (rc_code = xchg(&mixer->rc_code, 0)) != 0); if (err == 0) { - err = put_user(rc_code, buf); + if (count == 1) + err = put_user(rc_code, buf); + else + err = put_user(rc_code, (u32 __user *)buf); } return err < 0 ? err : count; } @@ -1758,6 +1773,25 @@ static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file, return mixer->rc_code ? POLLIN | POLLRDNORM : 0; } +static int snd_usb_sbrc_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + u32 __user *argp = (u32 __user *)arg; + u32 mode; + + switch (cmd) { + case LIRC_GET_FEATURES: + return put_user(LIRC_CAN_REC_CODE, argp); + case LIRC_GET_REC_MODE: + return put_user(LIRC_MODE_CODE, argp); + case LIRC_SET_REC_MODE: + if (get_user(mode, argp)) + return -EFAULT; + return mode == LIRC_MODE_CODE ? 0 : -ENOSYS; + } + return -ENOTTY; +} + static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) { snd_hwdep_t *hwdep; @@ -1788,6 +1822,7 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) hwdep->ops.open = snd_usb_sbrc_hwdep_open; hwdep->ops.release = snd_usb_sbrc_hwdep_release; hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; + hwdep->ops.ioctl = snd_usb_sbrc_hwdep_ioctl; mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); if (!mixer->rc_urb) -- cgit v0.10.2 From 93446edcd05589201f20cf8843e8c4f990c18ae4 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 3 May 2005 08:02:40 +0200 Subject: [ALSA] usb-audio - Audigy 2 NX blinkenlights USB generic driver Adds mixer controls for the CMSS/Dolby Digital/Power LEDs on the SB Audigy 2 NX. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index d90d6fa..ec880ff 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -83,6 +83,8 @@ struct usb_mixer_interface { struct urb *rc_urb; struct usb_ctrlrequest *rc_setup_packet; u8 rc_buffer[6]; + + u8 audigy2nx_leds[3]; }; @@ -1846,6 +1848,85 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) return 0; } +static int snd_audigy2nx_led_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_audigy2nx_led_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + int index = kcontrol->private_value; + + ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index]; + return 0; +} + +static int snd_audigy2nx_led_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + int index = kcontrol->private_value; + int value = ucontrol->value.integer.value[0]; + int err, changed; + + if (value > 1) + return -EINVAL; + changed = value != mixer->audigy2nx_leds[index]; + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + value, index + 2, NULL, 0, 100); + if (err < 0) + return err; + mixer->audigy2nx_leds[index] = value; + return changed; +} + +static snd_kcontrol_new_t snd_audigy2nx_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "CMSS LED Switch", + .info = snd_audigy2nx_led_info, + .get = snd_audigy2nx_led_get, + .put = snd_audigy2nx_led_put, + .private_value = 0, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Power LED Switch", + .info = snd_audigy2nx_led_info, + .get = snd_audigy2nx_led_get, + .put = snd_audigy2nx_led_put, + .private_value = 1, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Dolby Digital LED Switch", + .info = snd_audigy2nx_led_info, + .get = snd_audigy2nx_led_get, + .put = snd_audigy2nx_led_put, + .private_value = 2, + }, +}; + +static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) +{ + int i, err; + + for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { + err = snd_ctl_add(mixer->chip->card, + snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); + if (err < 0) + return err; + } + mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */ + return 0; +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1871,23 +1952,26 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) } if ((err = snd_usb_mixer_controls(mixer)) < 0 || - (err = snd_usb_mixer_status_create(mixer)) < 0) { - snd_usb_mixer_free(mixer); - return err; - } + (err = snd_usb_mixer_status_create(mixer)) < 0) + goto _error; - if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { - snd_usb_mixer_free(mixer); - return err; + if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) + goto _error; + + if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) { + if ((err = snd_audigy2nx_controls_create(mixer)) < 0) + goto _error; } err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); - if (err < 0) { - snd_usb_mixer_free(mixer); - return err; - } + if (err < 0) + goto _error; list_add(&mixer->list, &chip->mixer_list); return 0; + +_error: + snd_usb_mixer_free(mixer); + return err; } void snd_usb_mixer_disconnect(struct list_head *p) -- cgit v0.10.2 From c3f9329716df9965cbaf74ce313a12fe889c1a62 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 4 May 2005 14:56:04 +0200 Subject: [ALSA] usb-audio - set sample rate attribute on Audigy 2 NX endpoints USB generic driver The SB Audigy 2 NX does not advertise the sample rate attribute in its endpoint descriptors although it supports it. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a5e97d0..da1fe0f 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2499,32 +2499,31 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) /* some quirks for attributes here */ - /* workaround for AudioTrak Optoplay */ - if (chip->usb_id == USB_ID(0x0a92, 0x0053)) { + switch (chip->usb_id) { + case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ /* Optoplay sets the sample rate attribute although * it seems not supporting it in fact. */ fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE; - } - - /* workaround for M-Audio Audiophile USB */ - if (chip->usb_id == USB_ID(0x0763, 0x2003)) { + break; + case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ /* doesn't set the sample rate attribute, but supports it */ fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; - } - + break; + case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ + case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is + an older model 77d:223) */ /* * plantronics headset and Griffin iMic have set adaptive-in * although it's really not... */ - if (chip->usb_id == USB_ID(0x047f, 0x0ca1) || - /* Griffin iMic (note that there is an older model 77d:223) */ - chip->usb_id == USB_ID(0x077d, 0x07af)) { fp->ep_attr &= ~EP_ATTR_MASK; if (stream == SNDRV_PCM_STREAM_PLAYBACK) fp->ep_attr |= EP_ATTR_ADAPTIVE; else fp->ep_attr |= EP_ATTR_SYNC; + break; } /* ok, let's parse further... */ -- cgit v0.10.2 From 14c7e472aa979eecc15255eec5cec2763649c599 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Wed, 4 May 2005 16:53:53 +0200 Subject: [ALSA] Update A_SAMPLE_RATE register details. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 61a3f418..23dabbc 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -805,10 +805,26 @@ #define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */ #define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */ -#define A_SPDIF_RATE_MASK 0x000000c0 +#define A_SAMPLE_RATE 0x76 /* Various sample rate settings. */ +#define A_SAMPLE_RATE_NOT_USED 0x0ffc111e /* Bits that are not used and cannot be set. */ +#define A_SAMPLE_RATE_UNKNOWN 0xf0030001 /* Bits that can be set, but have unknown use. */ +#define A_SPDIF_RATE_MASK 0x000000e0 /* Any other values for rates, just use 48000 */ #define A_SPDIF_48000 0x00000000 -#define A_SPDIF_44100 0x00000080 +#define A_SPDIF_192000 0x00000020 #define A_SPDIF_96000 0x00000040 +#define A_SPDIF_44100 0x00000080 + +#define A_I2S_CAPTURE_RATE_MASK 0x00000e00 /* This sets the capture PCM rate, but it is */ +#define A_I2S_CAPTURE_48000 0x00000000 /* unclear if this sets the ADC rate as well. */ +#define A_I2S_CAPTURE_192000 0x00000200 +#define A_I2S_CAPTURE_96000 0x00000400 +#define A_I2S_CAPTURE_44100 0x00000800 + +#define A_PCM_RATE_MASK 0x0000e000 /* This sets the playback PCM rate on the P16V */ +#define A_PCM_48000 0x00000000 +#define A_PCM_192000 0x00002000 +#define A_PCM_96000 0x00004000 +#define A_PCM_44100 0x00008000 /* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */ /* 0x7a, 0x7b - lookup tables */ -- cgit v0.10.2 From c702563703b5680a7143f8ac66613d082a190ca2 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Wed, 4 May 2005 17:26:28 +0200 Subject: [ALSA] Support multiple capture rates on p16v. EMU10K1/EMU10K2 driver The capture rate does in fact vary, but it only captures anything if the HD Capture source is set to I2S or AC97. I have not tested if the sound is actually captured from an physical input of some type or not. TODO: Get SPDIF capture working. Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 776761f..13f7e62 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -133,25 +133,24 @@ static snd_pcm_hardware_t snd_p16v_playback_hw = { }; static snd_pcm_hardware_t snd_p16v_capture_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = (32*1024), - .period_bytes_min = 64, - .period_bytes_max = (16*1024), - .periods_min = 2, - .periods_max = 2, - .fifo_size = 0, + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, + .rate_min = 44100, + .rate_max = 192000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = (32*1024), + .period_bytes_min = 64, + .period_bytes_max = (16*1024), + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0, }; - static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime) { emu10k1_pcm_t *epcm = runtime->private_data; @@ -362,7 +361,25 @@ static int snd_p16v_pcm_prepare_capture(snd_pcm_substream_t *substream) emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int channel = substream->pcm->device - emu->p16v_device_offset; - //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); + u32 tmp; + //printk("prepare capture:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); + tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); + switch (runtime->rate) { + case 44100: + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0800); + break; + case 96000: + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0400); + break; + case 192000: + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0200); + break; + case 48000: + default: + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0000); + break; + } + /* FIXME: Check emu->buffer.size before actually writing to it. */ snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes -- cgit v0.10.2 From f927c8fc648420ad8edd7e4699b4ba510c2e9c6b Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 7 May 2005 15:34:13 +0200 Subject: [ALSA] Implement different capture sources. EMU10K1/EMU10K2 driver e.g. When HD Capture source is set to SPDIF, setting HD Capture channel to 0 captures from CDROM digital input. setting HD Capture channel to 1 captures from SPDIF in. Signed-off-by: James Courtier-Dutton diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 23dabbc..c50b919 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1130,6 +1130,7 @@ struct _snd_emu10k1 { emu10k1_voice_t p16v_capture_voice; int p16v_device_offset; u32 p16v_capture_source; + u32 p16v_capture_channel; emu10k1_pcm_mixer_t pcm_mixer[32]; emu10k1_pcm_mixer_t efx_pcm_mixer[NUM_EFX_PLAYBACK]; snd_kcontrol_t *ctl_send_routing; diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 13f7e62..93dff4c 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -41,7 +41,13 @@ * Integrated with snd-emu10k1 driver. * 0.22 * Removed #if 0 ... #endif - * + * 0.23 + * Implement different capture rates. + * 0.24 + * Implement different capture source channels. + * e.g. When HD Capture source is set to SPDIF, + * setting HD Capture channel to 0 captures from CDROM digital input. + * setting HD Capture channel to 1 captures from SPDIF in. * * BUGS: * Some stability problems when unloading the snd-p16v kernel module. @@ -933,6 +939,56 @@ static snd_kcontrol_new_t snd_p16v_capture_source __devinitdata = .get = snd_p16v_capture_source_get, .put = snd_p16v_capture_source_put }; + +static int snd_p16v_capture_channel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[4] = { "0", "1", "2", "3", }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item > 3) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_p16v_capture_channel_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->p16v_capture_channel; + return 0; +} + +static int snd_p16v_capture_channel_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + u32 tmp; + + val = ucontrol->value.enumerated.item[0] ; + change = (emu->p16v_capture_channel != val); + if (change) { + emu->p16v_capture_channel = val; + tmp = snd_emu10k1_ptr20_read(emu, CAPTURE_P16V_SOURCE, 0) & 0xfffc; + snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, tmp | val); + } + return change; +} + +static snd_kcontrol_new_t snd_p16v_capture_channel __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "HD Capture channel", + .info = snd_p16v_capture_channel_info, + .get = snd_p16v_capture_channel_get, + .put = snd_p16v_capture_channel_put +}; + int snd_p16v_mixer(emu10k1_t *emu) { int err; @@ -974,6 +1030,10 @@ int snd_p16v_mixer(emu10k1_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; + if ((kctl = snd_ctl_new1(&snd_p16v_capture_channel, emu)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(card, kctl))) + return err; return 0; } -- cgit v0.10.2 From 22bc30c84b4dc092deb2b14deb0603b257818e63 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 7 May 2005 16:13:40 +0200 Subject: [ALSA] Increase capture buffer sizes. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 93dff4c..98f9801 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -1,7 +1,7 @@ /* * Copyright (c) by James Courtier-Dutton * Driver p16v chips - * Version: 0.22 + * Version: 0.25 * * FEATURES currently supported: * Output fixed at S32_LE, 2 channel to hw:0,0 @@ -48,6 +48,8 @@ * e.g. When HD Capture source is set to SPDIF, * setting HD Capture channel to 0 captures from CDROM digital input. * setting HD Capture channel to 1 captures from SPDIF in. + * 0.25 + * Include capture buffer sizes. * * BUGS: * Some stability problems when unloading the snd-p16v kernel module. @@ -149,9 +151,9 @@ static snd_pcm_hardware_t snd_p16v_capture_hw = { .rate_max = 192000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = (32*1024), + .buffer_bytes_max = (65536 - 64), .period_bytes_min = 64, - .period_bytes_max = (16*1024), + .period_bytes_max = (65536 - 128) >> 1, /* size has to be N*64 bytes */ .periods_min = 2, .periods_max = 2, .fifo_size = 0, @@ -637,7 +639,7 @@ int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), - 64*1024, 64*1024)) < 0) + 65536 - 64, 65536 - 64)) < 0) return err; //snd_printk("preallocate capture substream: err=%d\n", err); } -- cgit v0.10.2 From a488e033861363f64ed90d01622e0c30b382b753 Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Sat, 7 May 2005 18:51:51 +0200 Subject: [ALSA] cs4281 - fix DLLRDY not seen problem CS4281 driver Reset the FPDN bit of the EPPMC register if needed. Signed-off-by: Arnaud Patard Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 8b42e86..b6e1854 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -206,7 +206,10 @@ MODULE_PARM_DESC(dual_codec, "Secondary Codec ID (0 = disabled)."); #define BA0_PMCS 0x0344 /* Power Management Control/Status */ #define BA0_CWPR 0x03e0 /* Configuration Write Protect */ + #define BA0_EPPMC 0x03e4 /* Extended PCI Power Management Control */ +#define BA0_EPPMC_FPDN (1<<14) /* Full Power DowN */ + #define BA0_GPIOR 0x03e8 /* GPIO Pin Interface Register */ #define BA0_SPMC 0x03ec /* Serial Port Power Management Control (& ASDIN2 enable) */ @@ -1461,6 +1464,11 @@ static int snd_cs4281_chip_init(cs4281_t *chip) int timeout; int retry_count = 2; + /* Having EPPMC.FPDN=1 prevent proper chip initialisation */ + tmp = snd_cs4281_peekBA0(chip, BA0_EPPMC); + if (tmp & BA0_EPPMC_FPDN) + snd_cs4281_pokeBA0(chip, BA0_EPPMC, tmp & ~BA0_EPPMC_FPDN); + __retry: tmp = snd_cs4281_peekBA0(chip, BA0_CFLR); if (tmp != BA0_CFLR_DEFAULT) { -- cgit v0.10.2 From 3714b5344e2da58d18f0b885663226826c22a1b3 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 8 May 2005 22:22:27 +0200 Subject: [ALSA] Fix snd-usb-audio dependency on snd-hwdep. USB Signed-off-by: James Courtier-Dutton diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 9329e99..f05d02f 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -6,6 +6,7 @@ menu "USB devices" config SND_USB_AUDIO tristate "USB Audio/MIDI driver" depends on SND && USB + select SND_HWDEP select SND_RAWMIDI select SND_PCM help -- cgit v0.10.2 From 3a2f08560d61e267aacddc63c26bf997d0d85e91 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 9 May 2005 09:20:31 +0200 Subject: [ALSA] usb-audio - enable high speed (not) on Audigy 2 NX USB generic driver The SB Audigy 2 NX needs a special boot-up command before it works in high speed mode. However, we don't actually enable it yet because high speed synchronization doesn't seem to work with this device. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index da1fe0f..34d5f58 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2925,6 +2925,25 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac return 0; } +static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) +{ +#if 0 + /* TODO: enable this when high speed synchronization actually works */ + u8 buf = 1; + + snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 0, 0, &buf, 1, 1000); + if (buf == 0) { + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 1, 2000, NULL, 0, 1000); + return -ENODEV; + } +#endif + return 0; +} + /* * audio-interface quirks @@ -3154,6 +3173,11 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __err_val; config = dev->actconfig; } + /* SB Audigy 2 NX needs its own boot-up magic, too */ + if (id == USB_ID(0x041e, 0x3020)) { + if (snd_usb_audigy2nx_boot_quirk(dev) < 0) + goto __err_val; + } /* * found a config. now register to ALSA -- cgit v0.10.2 From f55a655bf9eeb1431633bd313f47c8e4dadcf47c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 9 May 2005 09:21:28 +0200 Subject: [ALSA] usb-audio - remove superfluous LIRC ioctls USB generic driver The ioctls for LIRC compatibility can be removed because the infrastructure and detection stuff is better done in user space. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index ec880ff..4a49e19 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -39,19 +39,6 @@ #include "usbaudio.h" -#if 0 -#include -#else -/* only those symbols from lirc.h we actually need: */ -#include -#define LIRC_MODE2REC(x) ((x) << 16) -#define LIRC_MODE_CODE 0x00000008 -#define LIRC_CAN_REC_CODE LIRC_MODE2REC(LIRC_MODE_CODE) -#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) -#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) -#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) -#endif - /* */ @@ -1775,25 +1762,6 @@ static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file, return mixer->rc_code ? POLLIN | POLLRDNORM : 0; } -static int snd_usb_sbrc_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, - unsigned int cmd, unsigned long arg) -{ - u32 __user *argp = (u32 __user *)arg; - u32 mode; - - switch (cmd) { - case LIRC_GET_FEATURES: - return put_user(LIRC_CAN_REC_CODE, argp); - case LIRC_GET_REC_MODE: - return put_user(LIRC_MODE_CODE, argp); - case LIRC_SET_REC_MODE: - if (get_user(mode, argp)) - return -EFAULT; - return mode == LIRC_MODE_CODE ? 0 : -ENOSYS; - } - return -ENOTTY; -} - static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) { snd_hwdep_t *hwdep; @@ -1824,7 +1792,6 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) hwdep->ops.open = snd_usb_sbrc_hwdep_open; hwdep->ops.release = snd_usb_sbrc_hwdep_release; hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; - hwdep->ops.ioctl = snd_usb_sbrc_hwdep_ioctl; mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); if (!mixer->rc_urb) -- cgit v0.10.2 From aafad5629a949d0ad41180f8a746b6cd7654e317 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 May 2005 14:47:38 +0200 Subject: [ALSA] usb-audio - add a proc file for Audigy 2 NX jack status USB generic driver This patch adds a proc file for the SB Audigy 2 NX which shows the connection status of the various jacks. Unfortunately, no SPDIF input frequency (yet). Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 4a49e19..83ba665 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "usbaudio.h" @@ -1622,11 +1623,22 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, int unitid) { - /* SB remote control */ - if (mixer->rc_type != RC_NONE && unitid == 0) { - /* read control code from device memory */ + if (mixer->rc_type == RC_NONE) + return; + /* unit ids specific to Extigy/Audigy 2 NX: */ + switch (unitid) { + case 0: /* remote control */ mixer->rc_urb->dev = mixer->chip->dev; usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); + break; + case 4: /* digital in jack */ + case 7: /* line in jacks */ + case 19: /* speaker out jacks */ + case 20: /* headphones out jack */ + break; + default: + snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); + break; } } @@ -1894,6 +1906,37 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) return 0; } +static void snd_audigy2nx_proc_read(snd_info_entry_t *entry, + snd_info_buffer_t *buffer) +{ + static const struct { + int unitid; + const char *name; + } jacks[] = { + {4, "dig in "}, + {7, "line in"}, + {19, "spk out"}, + {20, "hph out"}, + }; + struct usb_mixer_interface *mixer = entry->private_data; + int i, err; + u8 buf[3]; + + snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); + for (i = 0; i < ARRAY_SIZE(jacks); ++i) { + snd_iprintf(buffer, "%s: ", jacks[i].name); + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_rcvctrlpipe(mixer->chip->dev, 0), + GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, 0, + jacks[i].unitid << 8, buf, 3, 100); + if (err == 3 && buf[0] == 3) + snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); + else + snd_iprintf(buffer, "?\n"); + } +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1926,8 +1969,13 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) goto _error; if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) { + snd_info_entry_t *entry; + if ((err = snd_audigy2nx_controls_create(mixer)) < 0) goto _error; + if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) + snd_info_set_text_ops(entry, mixer, 1024, + snd_audigy2nx_proc_read); } err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); -- cgit v0.10.2 From 3296480674e127601f453db6301bfbcbacb0d123 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 May 2005 14:48:37 +0200 Subject: [ALSA] ac97 - fix Mic jack sharing on AD1888 codecs AC97 Codec The code for modifying the center/LFE disable bit on AD1888 codecs accidentally toggled the mute split bit instead. Signed-off-by: Clemens Ladisch diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 737c4bb..05efff0 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1507,7 +1507,7 @@ static void ad1888_update_jacks(ac97_t *ac97) is_shared_linein(ac97) ? 0 : 1 << 12); /* shared Mic */ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, - is_shared_micin(ac97) ? 0 : 1 << 13); + is_shared_micin(ac97) ? 0 : 1 << 11); } static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { -- cgit v0.10.2 From 462c4173509c5d1ebdc6cfd58f7236c2ac467e30 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 May 2005 14:50:31 +0200 Subject: [ALSA] ac97 - enable multichannel output on AD198x codecs AC97 Codec The code for AD1980/AD1985/AD1986 codecs forgot to enable the code to switch the jack sharing bits on AD1888-compatible codecs. Signed-off-by: Clemens Ladisch diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 05efff0..ce02e70 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1585,8 +1585,9 @@ static struct snd_ac97_build_ops patch_ad1980_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1980_specific, #ifdef CONFIG_PM - .resume = ad18xx_resume + .resume = ad18xx_resume, #endif + .update_jacks = ad1888_update_jacks, }; int patch_ad1980(ac97_t * ac97) @@ -1614,8 +1615,9 @@ static struct snd_ac97_build_ops patch_ad1985_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1985_specific, #ifdef CONFIG_PM - .resume = ad18xx_resume + .resume = ad18xx_resume, #endif + .update_jacks = ad1888_update_jacks, }; int patch_ad1985(ac97_t * ac97) -- cgit v0.10.2 From 1dcd3ec4728f9568ee204ceb46b0851be324a7f9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 May 2005 14:51:40 +0200 Subject: [ALSA] usb-audio - bind to control interface instead of usb_device USB generic driver Bind the device files to the (first) audio control interface instead of the entire USB device. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 34d5f58..c360ab9 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3129,8 +3129,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, snd_usb_audio_create_proc(chip); - snd_card_set_dev(card, &dev->dev); - *rchip = chip; return 0; } @@ -3212,6 +3210,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { goto __error; } + snd_card_set_dev(chip->card, &intf->dev); break; } if (! chip) { -- cgit v0.10.2 From f7de9cfd25b6867a2854d98d734e03e1a9fc65fb Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Wed, 11 May 2005 11:13:26 +0200 Subject: [ALSA] emu10k1 - add SB0060 to emu_chip_details EMU10K1/EMU10K2 driver The following patch adds SB0060 to emu_chip_details. Signed-off-by: Mikael Magnusson Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index bf17db1..070be6a 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -711,6 +711,12 @@ static emu_chip_details_t emu_chip_details[] = { .id = "APS", .emu10k1_chip = 1, .ecard = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102, + .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, .driver = "EMU10K1", .name = "SB Live 5.1", .id = "Live", -- cgit v0.10.2 From 9b9a5afffd8636a82c6b32970342aef9d1f3d17d Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 May 2005 10:25:58 +0200 Subject: [ALSA] ARM DMA subsystem ARM DMA routines The patch below adds a convenient re-usable shim around the extended ARM DMA API, and is used by several ARM ALSA drivers. Signed-off-by: Russell King Signed-off-by: Takashi Iwai diff --git a/sound/arm/devdma.c b/sound/arm/devdma.c new file mode 100644 index 0000000..60826a5 --- /dev/null +++ b/sound/arm/devdma.c @@ -0,0 +1,81 @@ +/* + * linux/sound/arm/devdma.c + * + * Copyright (C) 2003-2004 Russell King, All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ARM DMA shim for ALSA. + */ +#include +#include + +#include +#include +#include + +#include "devdma.h" + +void devdma_hw_free(struct device *dev, snd_pcm_substream_t *substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct snd_dma_buffer *buf = runtime->dma_buffer_p; + + if (runtime->dma_area == NULL) + return; + + if (buf != &substream->dma_buffer) { + dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr); + kfree(runtime->dma_buffer_p); + } + + snd_pcm_set_runtime_buffer(substream, NULL); +} + +int devdma_hw_alloc(struct device *dev, snd_pcm_substream_t *substream, size_t size) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct snd_dma_buffer *buf = runtime->dma_buffer_p; + int ret = 0; + + if (buf) { + if (buf->bytes >= size) + goto out; + devdma_hw_free(dev, substream); + } + + if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { + buf = &substream->dma_buffer; + } else { + buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); + if (!buf) + goto nomem; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = dev; + buf->area = dma_alloc_coherent(dev, size, &buf->addr, GFP_KERNEL); + buf->bytes = size; + buf->private_data = NULL; + + if (!buf->area) + goto free; + } + snd_pcm_set_runtime_buffer(substream, buf); + ret = 1; + out: + runtime->dma_bytes = size; + return ret; + + free: + kfree(buf); + nomem: + return -ENOMEM; +} + +int devdma_mmap(struct device *dev, snd_pcm_substream_t *substream, struct vm_area_struct *vma) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); +} diff --git a/sound/arm/devdma.h b/sound/arm/devdma.h new file mode 100644 index 0000000..5a33b6b --- /dev/null +++ b/sound/arm/devdma.h @@ -0,0 +1,3 @@ +void devdma_hw_free(struct device *dev, snd_pcm_substream_t *substream); +int devdma_hw_alloc(struct device *dev, snd_pcm_substream_t *substream, size_t size); +int devdma_mmap(struct device *dev, snd_pcm_substream_t *substream, struct vm_area_struct *vma); -- cgit v0.10.2 From cb5a6ffc5c09bc354af69407dae710dcddcced37 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 May 2005 14:04:59 +0200 Subject: [ALSA] ARM AACI primecell driver ARM,/arm/Makefile,ARM AACI PL041 driver Add support for the ARM AACI Primecell, which provides an AC'97 based interface. This driver only provides playback support. This has been extensively tested with an LM4549 AC'97 codec. Signed-off-by: Russell King Signed-off-by: Takashi Iwai diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index cdacf4d..34c1740 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -14,5 +14,11 @@ config SND_SA11XX_UDA1341 To compile this driver as a module, choose M here: the module will be called snd-sa11xx-uda1341. +config SND_ARMAACI + tristate "ARM PrimeCell PL041 AC Link support" + depends on SND && ARM_AMBA + select SND_PCM + select SND_AC97_CODEC + endmenu diff --git a/sound/arm/Makefile b/sound/arm/Makefile index d7e7dc0..f74ec28 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -6,3 +6,6 @@ snd-sa11xx-uda1341-objs := sa11xx-uda1341.o # Toplevel Module Dependency obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o + +obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o +snd-aaci-objs := aaci.o devdma.o diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c new file mode 100644 index 0000000..08cc3dd --- /dev/null +++ b/sound/arm/aaci.c @@ -0,0 +1,968 @@ +/* + * linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Documentation: ARM DDI 0173B + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "aaci.h" +#include "devdma.h" + +#define DRIVER_NAME "aaci-pl041" + +/* + * PM support is not complete. Turn it off. + */ +#undef CONFIG_PM + +static void aaci_ac97_select_codec(struct aaci *aaci, ac97_t *ac97) +{ + u32 v, maincr = aaci->maincr | MAINCR_SCRA(ac97->num); + + /* + * Ensure that the slot 1/2 RX registers are empty. + */ + v = readl(aaci->base + AACI_SLFR); + if (v & SLFR_2RXV) + readl(aaci->base + AACI_SL2RX); + if (v & SLFR_1RXV) + readl(aaci->base + AACI_SL1RX); + + writel(maincr, aaci->base + AACI_MAINCR); +} + +/* + * P29: + * The recommended use of programming the external codec through slot 1 + * and slot 2 data is to use the channels during setup routines and the + * slot register at any other time. The data written into slot 1, slot 2 + * and slot 12 registers is transmitted only when their corresponding + * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR + * register. + */ +static void aaci_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) +{ + struct aaci *aaci = ac97->private_data; + u32 v; + + if (ac97->num >= 4) + return; + + down(&aaci->ac97_sem); + + aaci_ac97_select_codec(aaci, ac97); + + /* + * P54: You must ensure that AACI_SL2TX is always written + * to, if required, before data is written to AACI_SL1TX. + */ + writel(val << 4, aaci->base + AACI_SL2TX); + writel(reg << 12, aaci->base + AACI_SL1TX); + + /* + * Wait for the transmission of both slots to complete. + */ + do { + v = readl(aaci->base + AACI_SLFR); + } while (v & (SLFR_1TXB|SLFR_2TXB)); + + up(&aaci->ac97_sem); +} + +/* + * Read an AC'97 register. + */ +static unsigned short aaci_ac97_read(ac97_t *ac97, unsigned short reg) +{ + struct aaci *aaci = ac97->private_data; + u32 v; + + if (ac97->num >= 4) + return ~0; + + down(&aaci->ac97_sem); + + aaci_ac97_select_codec(aaci, ac97); + + /* + * Write the register address to slot 1. + */ + writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX); + + /* + * Wait for the transmission to complete. + */ + do { + v = readl(aaci->base + AACI_SLFR); + } while (v & SLFR_1TXB); + + /* + * Give the AC'97 codec more than enough time + * to respond. (42us = ~2 frames at 48kHz.) + */ + udelay(42); + + /* + * Wait for slot 2 to indicate data. + */ + do { + cond_resched(); + v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); + } while (v != (SLFR_1RXV|SLFR_2RXV)); + + v = readl(aaci->base + AACI_SL1RX) >> 12; + if (v == reg) { + v = readl(aaci->base + AACI_SL2RX) >> 4; + } else { + dev_err(&aaci->dev->dev, + "wrong ac97 register read back (%x != %x)\n", + v, reg); + v = ~0; + } + + up(&aaci->ac97_sem); + return v; +} + +static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun) +{ + u32 val; + int timeout = 5000; + + do { + val = readl(aacirun->base + AACI_SR); + } while (val & (SR_TXB|SR_RXB) && timeout--); +} + + + +/* + * Interrupt support. + */ +static void aaci_fifo_irq(struct aaci *aaci, u32 mask) +{ + if (mask & ISR_URINTR) { + writel(ICLR_TXUEC1, aaci->base + AACI_INTCLR); + } + + if (mask & ISR_TXINTR) { + struct aaci_runtime *aacirun = &aaci->playback; + void *ptr; + + if (!aacirun->substream || !aacirun->start) { + dev_warn(&aaci->dev->dev, "TX interrupt???"); + writel(0, aacirun->base + AACI_IE); + return; + } + + ptr = aacirun->ptr; + do { + unsigned int len = aacirun->fifosz; + u32 val; + + if (aacirun->bytes <= 0) { + aacirun->bytes += aacirun->period; + aacirun->ptr = ptr; + spin_unlock(&aaci->lock); + snd_pcm_period_elapsed(aacirun->substream); + spin_lock(&aaci->lock); + } + if (!(aacirun->cr & TXCR_TXEN)) + break; + + val = readl(aacirun->base + AACI_SR); + if (!(val & SR_TXHE)) + break; + if (!(val & SR_TXFE)) + len >>= 1; + + aacirun->bytes -= len; + + /* writing 16 bytes at a time */ + for ( ; len > 0; len -= 16) { + asm( + "ldmia %0!, {r0, r1, r2, r3}\n\t" + "stmia %1, {r0, r1, r2, r3}" + : "+r" (ptr) + : "r" (aacirun->fifo) + : "r0", "r1", "r2", "r3", "cc"); + + if (ptr >= aacirun->end) + ptr = aacirun->start; + } + } while (1); + + aacirun->ptr = ptr; + } +} + +static irqreturn_t aaci_irq(int irq, void *devid, struct pt_regs *regs) +{ + struct aaci *aaci = devid; + u32 mask; + int i; + + spin_lock(&aaci->lock); + mask = readl(aaci->base + AACI_ALLINTS); + if (mask) { + u32 m = mask; + for (i = 0; i < 4; i++, m >>= 7) { + if (m & 0x7f) { + aaci_fifo_irq(aaci, m); + } + } + } + spin_unlock(&aaci->lock); + + return mask ? IRQ_HANDLED : IRQ_NONE; +} + + + +/* + * ALSA support. + */ + +struct aaci_stream { + unsigned char codec_idx; + unsigned char rate_idx; +}; + +static struct aaci_stream aaci_streams[] = { + [ACSTREAM_FRONT] = { + .codec_idx = 0, + .rate_idx = AC97_RATES_FRONT_DAC, + }, + [ACSTREAM_SURROUND] = { + .codec_idx = 0, + .rate_idx = AC97_RATES_SURR_DAC, + }, + [ACSTREAM_LFE] = { + .codec_idx = 0, + .rate_idx = AC97_RATES_LFE_DAC, + }, +}; + +static inline unsigned int aaci_rate_mask(struct aaci *aaci, int streamid) +{ + struct aaci_stream *s = aaci_streams + streamid; + return aaci->ac97_bus->codec[s->codec_idx]->rates[s->rate_idx]; +} + +static unsigned int rate_list[] = { + 5512, 8000, 11025, 16000, 22050, 32000, 44100, + 48000, 64000, 88200, 96000, 176400, 192000 +}; + +/* + * Double-rate rule: we can support double rate iff channels == 2 + * (unimplemented) + */ +static int +aaci_rule_rate_by_channels(snd_pcm_hw_params_t *p, snd_pcm_hw_rule_t *rule) +{ + struct aaci *aaci = rule->private; + unsigned int rate_mask = SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_5512; + snd_interval_t *c = hw_param_interval(p, SNDRV_PCM_HW_PARAM_CHANNELS); + + switch (c->max) { + case 6: + rate_mask &= aaci_rate_mask(aaci, ACSTREAM_LFE); + case 4: + rate_mask &= aaci_rate_mask(aaci, ACSTREAM_SURROUND); + case 2: + rate_mask &= aaci_rate_mask(aaci, ACSTREAM_FRONT); + } + + return snd_interval_list(hw_param_interval(p, rule->var), + ARRAY_SIZE(rate_list), rate_list, + rate_mask); +} + +static snd_pcm_hardware_t aaci_hw_info = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_RESUME, + + /* + * ALSA doesn't support 18-bit or 20-bit packed into 32-bit + * words. It also doesn't support 12-bit at all. + */ + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + /* should this be continuous or knot? */ + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_max = 48000, + .rate_min = 4000, + .channels_min = 2, + .channels_max = 6, + .buffer_bytes_max = 64 * 1024, + .period_bytes_min = 256, + .period_bytes_max = PAGE_SIZE, + .periods_min = 4, + .periods_max = PAGE_SIZE / 16, +}; + +static int aaci_pcm_open(struct aaci *aaci, snd_pcm_substream_t *substream, + struct aaci_runtime *aacirun) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + int ret; + + aacirun->substream = substream; + runtime->private_data = aacirun; + runtime->hw = aaci_hw_info; + + /* + * FIXME: ALSA specifies fifo_size in bytes. If we're in normal + * mode, each 32-bit word contains one sample. If we're in + * compact mode, each 32-bit word contains two samples, effectively + * halving the FIFO size. However, we don't know for sure which + * we'll be using at this point. We set this to the lower limit. + */ + runtime->hw.fifo_size = aaci->fifosize * 2; + + /* + * Add rule describing hardware rate dependency + * on the number of channels. + */ + ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + aaci_rule_rate_by_channels, aaci, + SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (ret) + goto out; + + ret = request_irq(aaci->dev->irq[0], aaci_irq, SA_SHIRQ|SA_INTERRUPT, + DRIVER_NAME, aaci); + if (ret) + goto out; + + return 0; + + out: + return ret; +} + + +/* + * Common ALSA stuff + */ +static int aaci_pcm_close(snd_pcm_substream_t *substream) +{ + struct aaci *aaci = substream->private_data; + struct aaci_runtime *aacirun = substream->runtime->private_data; + + WARN_ON(aacirun->cr & TXCR_TXEN); + + aacirun->substream = NULL; + free_irq(aaci->dev->irq[0], aaci); + + return 0; +} + +static int aaci_pcm_hw_free(snd_pcm_substream_t *substream) +{ + struct aaci_runtime *aacirun = substream->runtime->private_data; + + /* + * This must not be called with the device enabled. + */ + WARN_ON(aacirun->cr & TXCR_TXEN); + + if (aacirun->pcm_open) + snd_ac97_pcm_close(aacirun->pcm); + aacirun->pcm_open = 0; + + /* + * Clear out the DMA and any allocated buffers. + */ + devdma_hw_free(NULL, substream); + + return 0; +} + +static int aaci_pcm_hw_params(snd_pcm_substream_t *substream, + struct aaci_runtime *aacirun, + snd_pcm_hw_params_t *params) +{ + int err; + + aaci_pcm_hw_free(substream); + + err = devdma_hw_alloc(NULL, substream, + params_buffer_bytes(params)); + if (err < 0) + goto out; + + err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), + params_channels(params), + aacirun->pcm->r[0].slots); + if (err) + goto out; + + aacirun->pcm_open = 1; + + out: + return err; +} + +static int aaci_pcm_prepare(snd_pcm_substream_t *substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct aaci_runtime *aacirun = runtime->private_data; + + aacirun->start = (void *)runtime->dma_area; + aacirun->end = aacirun->start + runtime->dma_bytes; + aacirun->ptr = aacirun->start; + aacirun->period = + aacirun->bytes = frames_to_bytes(runtime, runtime->period_size); + + return 0; +} + +static snd_pcm_uframes_t aaci_pcm_pointer(snd_pcm_substream_t *substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct aaci_runtime *aacirun = runtime->private_data; + ssize_t bytes = aacirun->ptr - aacirun->start; + + return bytes_to_frames(runtime, bytes); +} + +static int aaci_pcm_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *vma) +{ + return devdma_mmap(NULL, substream, vma); +} + + +/* + * Playback specific ALSA stuff + */ +static const u32 channels_to_txmask[] = { + [2] = TXCR_TX3 | TXCR_TX4, + [4] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8, + [6] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8 | TXCR_TX6 | TXCR_TX9, +}; + +/* + * We can support two and four channel audio. Unfortunately + * six channel audio requires a non-standard channel ordering: + * 2 -> FL(3), FR(4) + * 4 -> FL(3), FR(4), SL(7), SR(8) + * 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required) + * FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual) + * This requires an ALSA configuration file to correct. + */ +static unsigned int channel_list[] = { 2, 4, 6 }; + +static int +aaci_rule_channels(snd_pcm_hw_params_t *p, snd_pcm_hw_rule_t *rule) +{ + struct aaci *aaci = rule->private; + unsigned int chan_mask = 1 << 0, slots; + + /* + * pcms[0] is the our 5.1 PCM instance. + */ + slots = aaci->ac97_bus->pcms[0].r[0].slots; + if (slots & (1 << AC97_SLOT_PCM_SLEFT)) { + chan_mask |= 1 << 1; + if (slots & (1 << AC97_SLOT_LFE)) + chan_mask |= 1 << 2; + } + + return snd_interval_list(hw_param_interval(p, rule->var), + ARRAY_SIZE(channel_list), channel_list, + chan_mask); +} + +static int aaci_pcm_playback_open(snd_pcm_substream_t *substream) +{ + struct aaci *aaci = substream->private_data; + int ret; + + /* + * Add rule describing channel dependency. + */ + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + aaci_rule_channels, aaci, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (ret) + return ret; + + return aaci_pcm_open(aaci, substream, &aaci->playback); +} + +static int aaci_pcm_playback_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *params) +{ + struct aaci *aaci = substream->private_data; + struct aaci_runtime *aacirun = substream->runtime->private_data; + unsigned int channels = params_channels(params); + int ret; + + WARN_ON(channels >= ARRAY_SIZE(channels_to_txmask) || + !channels_to_txmask[channels]); + + ret = aaci_pcm_hw_params(substream, aacirun, params); + + /* + * Enable FIFO, compact mode, 16 bits per sample. + * FIXME: double rate slots? + */ + if (ret >= 0) { + aacirun->cr = TXCR_FEN | TXCR_COMPACT | TXCR_TSZ16; + aacirun->cr |= channels_to_txmask[channels]; + + aacirun->fifosz = aaci->fifosize * 4; + if (aacirun->cr & TXCR_COMPACT) + aacirun->fifosz >>= 1; + } + return ret; +} + +static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) +{ + u32 ie; + + ie = readl(aacirun->base + AACI_IE); + ie &= ~(IE_URIE|IE_TXIE); + writel(ie, aacirun->base + AACI_IE); + aacirun->cr &= ~TXCR_TXEN; + aaci_chan_wait_ready(aacirun); + writel(aacirun->cr, aacirun->base + AACI_TXCR); +} + +static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) +{ + u32 ie; + + aaci_chan_wait_ready(aacirun); + aacirun->cr |= TXCR_TXEN; + + ie = readl(aacirun->base + AACI_IE); + ie |= IE_URIE | IE_TXIE; + writel(ie, aacirun->base + AACI_IE); + writel(aacirun->cr, aacirun->base + AACI_TXCR); +} + +static int aaci_pcm_playback_trigger(snd_pcm_substream_t *substream, int cmd) +{ + struct aaci *aaci = substream->private_data; + struct aaci_runtime *aacirun = substream->runtime->private_data; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&aaci->lock, flags); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + aaci_pcm_playback_start(aacirun); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + aaci_pcm_playback_start(aacirun); + break; + + case SNDRV_PCM_TRIGGER_STOP: + aaci_pcm_playback_stop(aacirun); + break; + + case SNDRV_PCM_TRIGGER_SUSPEND: + aaci_pcm_playback_stop(aacirun); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + break; + + default: + ret = -EINVAL; + } + spin_unlock_irqrestore(&aaci->lock, flags); + + return ret; +} + +static snd_pcm_ops_t aaci_playback_ops = { + .open = aaci_pcm_playback_open, + .close = aaci_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = aaci_pcm_playback_hw_params, + .hw_free = aaci_pcm_hw_free, + .prepare = aaci_pcm_prepare, + .trigger = aaci_pcm_playback_trigger, + .pointer = aaci_pcm_pointer, + .mmap = aaci_pcm_mmap, +}; + + + +/* + * Power Management. + */ +#ifdef CONFIG_PM +static int aaci_do_suspend(snd_card_t *card, unsigned int state) +{ + struct aaci *aaci = card->private_data; + if (aaci->card->power_state != SNDRV_CTL_POWER_D3cold) { + snd_pcm_suspend_all(aaci->pcm); + snd_power_change_state(aaci->card, SNDRV_CTL_POWER_D3cold); + } + return 0; +} + +static int aaci_do_resume(snd_card_t *card, unsigned int state) +{ + struct aaci *aaci = card->private_data; + if (aaci->card->power_state != SNDRV_CTL_POWER_D0) { + snd_power_change_state(aaci->card, SNDRV_CTL_POWER_D0); + } + return 0; +} + +static int aaci_suspend(struct amba_device *dev, u32 state) +{ + snd_card_t *card = amba_get_drvdata(dev); + return card ? aaci_do_suspend(card) : 0; +} + +static int aaci_resume(struct amba_device *dev) +{ + snd_card_t *card = amba_get_drvdata(dev); + return card ? aaci_do_resume(card) : 0; +} +#else +#define aaci_do_suspend NULL +#define aaci_do_resume NULL +#define aaci_suspend NULL +#define aaci_resume NULL +#endif + + +static struct ac97_pcm ac97_defs[] __devinitdata = { + [0] = { /* Front PCM */ + .exclusive = 1, + .r = { + [0] = { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) | + (1 << AC97_SLOT_PCM_CENTER) | + (1 << AC97_SLOT_PCM_SLEFT) | + (1 << AC97_SLOT_PCM_SRIGHT) | + (1 << AC97_SLOT_LFE), + }, + }, + }, + [1] = { /* PCM in */ + .stream = 1, + .exclusive = 1, + .r = { + [0] = { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT), + }, + }, + }, + [2] = { /* Mic in */ + .stream = 1, + .exclusive = 1, + .r = { + [0] = { + .slots = (1 << AC97_SLOT_MIC), + }, + }, + } +}; + +static ac97_bus_ops_t aaci_bus_ops = { + .write = aaci_ac97_write, + .read = aaci_ac97_read, +}; + +static int __devinit aaci_probe_ac97(struct aaci *aaci) +{ + ac97_template_t ac97_template; + ac97_bus_t *ac97_bus; + ac97_t *ac97; + int ret; + + /* + * Assert AACIRESET for 2us + */ + writel(0, aaci->base + AACI_RESET); + udelay(2); + writel(RESET_NRST, aaci->base + AACI_RESET); + + /* + * Give the AC'97 codec more than enough time + * to wake up. (42us = ~2 frames at 48kHz.) + */ + udelay(42); + + ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus); + if (ret) + goto out; + + ac97_bus->clock = 48000; + aaci->ac97_bus = ac97_bus; + + memset(&ac97_template, 0, sizeof(ac97_template_t)); + ac97_template.private_data = aaci; + ac97_template.num = 0; + ac97_template.scaps = AC97_SCAP_SKIP_MODEM; + + ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); + if (ret) + goto out; + + /* + * Disable AC97 PC Beep input on audio codecs. + */ + if (ac97_is_audio(ac97)) + snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e); + + ret = snd_ac97_pcm_assign(ac97_bus, ARRAY_SIZE(ac97_defs), ac97_defs); + if (ret) + goto out; + + aaci->playback.pcm = &ac97_bus->pcms[0]; + + out: + return ret; +} + +static void aaci_free_card(snd_card_t *card) +{ + struct aaci *aaci = card->private_data; + if (aaci->base) + iounmap(aaci->base); +} + +static struct aaci * __devinit aaci_init_card(struct amba_device *dev) +{ + struct aaci *aaci; + snd_card_t *card; + + card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, sizeof(struct aaci)); + if (card == NULL) + return ERR_PTR(-ENOMEM); + + card->private_free = aaci_free_card; + snd_card_set_pm_callback(card, aaci_do_suspend, aaci_do_resume, NULL); + + strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); + strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%08lx, irq %d", + card->shortname, dev->res.start, dev->irq[0]); + + aaci = card->private_data; + init_MUTEX(&aaci->ac97_sem); + spin_lock_init(&aaci->lock); + aaci->card = card; + aaci->dev = dev; + + /* Set MAINCR to allow slot 1 and 2 data IO */ + aaci->maincr = MAINCR_IE | MAINCR_SL1RXEN | MAINCR_SL1TXEN | + MAINCR_SL2RXEN | MAINCR_SL2TXEN; + + return aaci; +} + +static int __devinit aaci_init_pcm(struct aaci *aaci) +{ + snd_pcm_t *pcm; + int ret; + + ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 0, &pcm); + if (ret == 0) { + aaci->pcm = pcm; + pcm->private_data = aaci; + pcm->info_flags = 0; + + strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); + } + + return ret; +} + +static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) +{ + void *base = aaci->base + AACI_CSCH1; + int i; + + writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR); + + for (i = 0; !(readl(base + AACI_SR) & SR_TXFF) && i < 4096; i++) + writel(0, aaci->base + AACI_DR1); + + writel(0, base + AACI_TXCR); + + /* + * Re-initialise the AACI after the FIFO depth test, to + * ensure that the FIFOs are empty. Unfortunately, merely + * disabling the channel doesn't clear the FIFO. + */ + writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR); + writel(aaci->maincr, aaci->base + AACI_MAINCR); + + /* + * If we hit 4096, we failed. Go back to the specified + * fifo depth. + */ + if (i == 4096) + i = 8; + + return i; +} + +static int __devinit aaci_probe(struct amba_device *dev, void *id) +{ + struct aaci *aaci; + int ret, i; + + ret = amba_request_regions(dev, NULL); + if (ret) + return ret; + + aaci = aaci_init_card(dev); + if (IS_ERR(aaci)) { + ret = PTR_ERR(aaci); + goto out; + } + + aaci->base = ioremap(dev->res.start, SZ_4K); + if (!aaci->base) { + ret = -ENOMEM; + goto out; + } + + /* + * Playback uses AACI channel 0 + */ + aaci->playback.base = aaci->base + AACI_CSCH1; + aaci->playback.fifo = aaci->base + AACI_DR1; + + for (i = 0; i < 4; i++) { + void *base = aaci->base + i * 0x14; + + writel(0, base + AACI_IE); + writel(0, base + AACI_TXCR); + writel(0, base + AACI_RXCR); + } + + writel(0x1fff, aaci->base + AACI_INTCLR); + writel(aaci->maincr, aaci->base + AACI_MAINCR); + + /* + * Size the FIFOs. + */ + aaci->fifosize = aaci_size_fifo(aaci); + + ret = aaci_probe_ac97(aaci); + if (ret) + goto out; + + ret = aaci_init_pcm(aaci); + if (ret) + goto out; + + ret = snd_card_register(aaci->card); + if (ret == 0) { + dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname, + aaci->fifosize); + amba_set_drvdata(dev, aaci->card); + return ret; + } + + out: + if (aaci) + snd_card_free(aaci->card); + amba_release_regions(dev); + return ret; +} + +static int __devexit aaci_remove(struct amba_device *dev) +{ + snd_card_t *card = amba_get_drvdata(dev); + + amba_set_drvdata(dev, NULL); + + if (card) { + struct aaci *aaci = card->private_data; + writel(0, aaci->base + AACI_MAINCR); + + snd_card_free(card); + amba_release_regions(dev); + } + + return 0; +} + +static struct amba_id aaci_ids[] = { + { + .id = 0x00041041, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver aaci_driver = { + .drv = { + .name = DRIVER_NAME, + }, + .probe = aaci_probe, + .remove = __devexit_p(aaci_remove), + .suspend = aaci_suspend, + .resume = aaci_resume, + .id_table = aaci_ids, +}; + +static int __init aaci_init(void) +{ + return amba_driver_register(&aaci_driver); +} + +static void __exit aaci_exit(void) +{ + amba_driver_unregister(&aaci_driver); +} + +module_init(aaci_init); +module_exit(aaci_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver"); diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h new file mode 100644 index 0000000..d752e64 --- /dev/null +++ b/sound/arm/aaci.h @@ -0,0 +1,246 @@ +/* + * linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef AACI_H +#define AACI_H + +/* + * Control and status register offsets + * P39. + */ +#define AACI_CSCH1 0x000 +#define AACI_CSCH2 0x014 +#define AACI_CSCH3 0x028 +#define AACI_CSCH4 0x03c + +#define AACI_RXCR 0x000 /* 29 bits Control Rx FIFO */ +#define AACI_TXCR 0x004 /* 17 bits Control Tx FIFO */ +#define AACI_SR 0x008 /* 12 bits Status */ +#define AACI_ISR 0x00c /* 7 bits Int Status */ +#define AACI_IE 0x010 /* 7 bits Int Enable */ + +/* + * Other registers + */ +#define AACI_SL1RX 0x050 +#define AACI_SL1TX 0x054 +#define AACI_SL2RX 0x058 +#define AACI_SL2TX 0x05c +#define AACI_SL12RX 0x060 +#define AACI_SL12TX 0x064 +#define AACI_SLFR 0x068 /* slot flags */ +#define AACI_SLISTAT 0x06c /* slot interrupt status */ +#define AACI_SLIEN 0x070 /* slot interrupt enable */ +#define AACI_INTCLR 0x074 /* interrupt clear */ +#define AACI_MAINCR 0x078 /* main control */ +#define AACI_RESET 0x07c /* reset control */ +#define AACI_SYNC 0x080 /* sync control */ +#define AACI_ALLINTS 0x084 /* all fifo interrupt status */ +#define AACI_MAINFR 0x088 /* main flag register */ +#define AACI_DR1 0x090 /* data read/written fifo 1 */ +#define AACI_DR2 0x0b0 /* data read/written fifo 2 */ +#define AACI_DR3 0x0d0 /* data read/written fifo 3 */ +#define AACI_DR4 0x0f0 /* data read/written fifo 4 */ + +/* + * transmit fifo control register. P48 + */ +#define TXCR_FEN (1 << 16) /* fifo enable */ +#define TXCR_COMPACT (1 << 15) /* compact mode */ +#define TXCR_TSZ16 (0 << 13) /* 16 bits */ +#define TXCR_TSZ18 (1 << 13) /* 18 bits */ +#define TXCR_TSZ20 (2 << 13) /* 20 bits */ +#define TXCR_TSZ12 (3 << 13) /* 12 bits */ +#define TXCR_TX12 (1 << 12) /* transmits slot 12 */ +#define TXCR_TX11 (1 << 11) /* transmits slot 12 */ +#define TXCR_TX10 (1 << 10) /* transmits slot 12 */ +#define TXCR_TX9 (1 << 9) /* transmits slot 12 */ +#define TXCR_TX8 (1 << 8) /* transmits slot 12 */ +#define TXCR_TX7 (1 << 7) /* transmits slot 12 */ +#define TXCR_TX6 (1 << 6) /* transmits slot 12 */ +#define TXCR_TX5 (1 << 5) /* transmits slot 12 */ +#define TXCR_TX4 (1 << 4) /* transmits slot 12 */ +#define TXCR_TX3 (1 << 3) /* transmits slot 12 */ +#define TXCR_TX2 (1 << 2) /* transmits slot 12 */ +#define TXCR_TX1 (1 << 1) /* transmits slot 12 */ +#define TXCR_TXEN (1 << 0) /* transmit enable */ + +/* + * status register bits. P49 + */ +#define SR_RXTOFE (1 << 11) /* rx timeout fifo empty */ +#define SR_TXTO (1 << 10) /* rx timeout fifo nonempty */ +#define SR_TXU (1 << 9) /* tx underrun */ +#define SR_RXO (1 << 8) /* rx overrun */ +#define SR_TXB (1 << 7) /* tx busy */ +#define SR_RXB (1 << 6) /* rx busy */ +#define SR_TXFF (1 << 5) /* tx fifo full */ +#define SR_RXFF (1 << 4) /* rx fifo full */ +#define SR_TXHE (1 << 3) /* tx fifo half empty */ +#define SR_RXHF (1 << 2) /* rx fifo half full */ +#define SR_TXFE (1 << 1) /* tx fifo empty */ +#define SR_RXFE (1 << 0) /* rx fifo empty */ + +/* + * interrupt status register bits. + */ +#define ISR_RXTOFEINTR (1 << 6) /* rx fifo empty */ +#define ISR_URINTR (1 << 5) /* tx underflow */ +#define ISR_ORINTR (1 << 4) /* rx overflow */ +#define ISR_RXINTR (1 << 3) /* rx fifo */ +#define ISR_TXINTR (1 << 2) /* tx fifo intr */ +#define ISR_RXTOINTR (1 << 1) /* tx timeout */ +#define ISR_TXCINTR (1 << 0) /* tx complete */ + +/* + * interrupt enable register bits. + */ +#define IE_RXTOIE (1 << 6) +#define IE_URIE (1 << 5) +#define IE_ORIE (1 << 4) +#define IE_RXIE (1 << 3) +#define IE_TXIE (1 << 2) +#define IE_RXTIE (1 << 1) +#define IE_TXCIE (1 << 0) + +/* + * interrupt status. P51 + */ +#define ISR_RXTOFE (1 << 6) /* rx timeout fifo empty */ +#define ISR_UR (1 << 5) /* tx fifo underrun */ +#define ISR_OR (1 << 4) /* rx fifo overrun */ +#define ISR_RX (1 << 3) /* rx interrupt status */ +#define ISR_TX (1 << 2) /* tx interrupt status */ +#define ISR_RXTO (1 << 1) /* rx timeout */ +#define ISR_TXC (1 << 0) /* tx complete */ + +/* + * interrupt enable. P52 + */ +#define IE_RXTOFE (1 << 6) /* rx timeout fifo empty */ +#define IE_UR (1 << 5) /* tx fifo underrun */ +#define IE_OR (1 << 4) /* rx fifo overrun */ +#define IE_RX (1 << 3) /* rx interrupt status */ +#define IE_TX (1 << 2) /* tx interrupt status */ +#define IE_RXTO (1 << 1) /* rx timeout */ +#define IE_TXC (1 << 0) /* tx complete */ + +/* + * slot flag register bits. P56 + */ +#define SLFR_RWIS (1 << 13) /* raw wake-up interrupt status */ +#define SLFR_RGPIOINTR (1 << 12) /* raw gpio interrupt */ +#define SLFR_12TXE (1 << 11) /* slot 12 tx empty */ +#define SLFR_12RXV (1 << 10) /* slot 12 rx valid */ +#define SLFR_2TXE (1 << 9) /* slot 2 tx empty */ +#define SLFR_2RXV (1 << 8) /* slot 2 rx valid */ +#define SLFR_1TXE (1 << 7) /* slot 1 tx empty */ +#define SLFR_1RXV (1 << 6) /* slot 1 rx valid */ +#define SLFR_12TXB (1 << 5) /* slot 12 tx busy */ +#define SLFR_12RXB (1 << 4) /* slot 12 rx busy */ +#define SLFR_2TXB (1 << 3) /* slot 2 tx busy */ +#define SLFR_2RXB (1 << 2) /* slot 2 rx busy */ +#define SLFR_1TXB (1 << 1) /* slot 1 tx busy */ +#define SLFR_1RXB (1 << 0) /* slot 1 rx busy */ + +/* + * Interrupt clear register. + */ +#define ICLR_RXTOFEC4 (1 << 12) +#define ICLR_RXTOFEC3 (1 << 11) +#define ICLR_RXTOFEC2 (1 << 10) +#define ICLR_RXTOFEC1 (1 << 9) +#define ICLR_TXUEC4 (1 << 8) +#define ICLR_TXUEC3 (1 << 7) +#define ICLR_TXUEC2 (1 << 6) +#define ICLR_TXUEC1 (1 << 5) +#define ICLR_RXOEC4 (1 << 4) +#define ICLR_RXOEC3 (1 << 3) +#define ICLR_RXOEC2 (1 << 2) +#define ICLR_RXOEC1 (1 << 1) +#define ICLR_WISC (1 << 0) + +/* + * Main control register bits. P62 + */ +#define MAINCR_SCRA(x) ((x) << 10) /* secondary codec reg access */ +#define MAINCR_DMAEN (1 << 9) /* dma enable */ +#define MAINCR_SL12TXEN (1 << 8) /* slot 12 transmit enable */ +#define MAINCR_SL12RXEN (1 << 7) /* slot 12 receive enable */ +#define MAINCR_SL2TXEN (1 << 6) /* slot 2 transmit enable */ +#define MAINCR_SL2RXEN (1 << 5) /* slot 2 receive enable */ +#define MAINCR_SL1TXEN (1 << 4) /* slot 1 transmit enable */ +#define MAINCR_SL1RXEN (1 << 3) /* slot 1 receive enable */ +#define MAINCR_LPM (1 << 2) /* low power mode */ +#define MAINCR_LOOPBK (1 << 1) /* loopback */ +#define MAINCR_IE (1 << 0) /* aaci interface enable */ + +/* + * Reset register bits. P65 + */ +#define RESET_NRST (1 << 0) + +/* + * Sync register bits. P65 + */ +#define SYNC_FORCE (1 << 0) + +/* + * Main flag register bits. P66 + */ +#define MAINFR_TXB (1 << 1) /* transmit busy */ +#define MAINFR_RXB (1 << 0) /* receive busy */ + + + +struct aaci_runtime { + void *base; + void *fifo; + + struct ac97_pcm *pcm; + int pcm_open; + + u32 cr; + snd_pcm_substream_t *substream; + + /* + * PIO support + */ + void *start; + void *end; + void *ptr; + int bytes; + unsigned int period; + unsigned int fifosz; +}; + +struct aaci { + struct amba_device *dev; + snd_card_t *card; + void *base; + unsigned int fifosize; + + /* AC'97 */ + struct semaphore ac97_sem; + ac97_bus_t *ac97_bus; + + u32 maincr; + spinlock_t lock; + + struct aaci_runtime playback; + struct aaci_runtime capture; + + snd_pcm_t *pcm; +}; + +#define ACSTREAM_FRONT 0 +#define ACSTREAM_SURROUND 1 +#define ACSTREAM_LFE 2 + +#endif -- cgit v0.10.2 From 88491386be67f659e6b2c76c7463c997ce4c4ebb Mon Sep 17 00:00:00 2001 From: Ville Syrjala Date: Thu, 12 May 2005 14:14:28 +0200 Subject: [ALSA] maestro3: Fix interrupt ack and disable Maestro3 driver Due to a typo interrupts were never actually acked or disabled. Signed-off-by: Ville Syrjala Signed-off-by: Takashi Iwai diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 9f184ea8..293cc10 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1605,7 +1605,7 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) #endif /* ack ints */ - snd_m3_outw(chip, HOST_INT_STATUS, status); + outb(status, chip->iobase + HOST_INT_STATUS); return IRQ_HANDLED; } @@ -2367,7 +2367,7 @@ static int snd_m3_free(m3_t *chip) kfree(chip->substreams); } if (chip->iobase) { - snd_m3_outw(chip, HOST_INT_CTRL, 0); /* disable ints */ + outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */ } #ifdef CONFIG_PM -- cgit v0.10.2 From db68d15da00f64bef2c8c822baab42aff39ae774 Mon Sep 17 00:00:00 2001 From: Ville Syrjala Date: Thu, 12 May 2005 14:19:32 +0200 Subject: [ALSA] maestro3: Add HW volume button support Maestro3 driver Add support for hardware volume buttons. Signed-off-by: Ville Syrjala Signed-off-by: Takashi Iwai diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 293cc10..c1c7eee 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -851,7 +851,12 @@ struct snd_m3 { m3_dma_t *substreams; spinlock_t reg_lock; + spinlock_t ac97_lock; + snd_kcontrol_t *master_switch; + snd_kcontrol_t *master_volume; + struct tasklet_struct hwvol_tq; + #ifdef CONFIG_PM u16 *suspend_mem; #endif @@ -1565,6 +1570,68 @@ static void snd_m3_update_ptr(m3_t *chip, m3_dma_t *s) } } +static void snd_m3_update_hw_volume(unsigned long private_data) +{ + m3_t *chip = (m3_t *) private_data; + int x, val; + unsigned long flags; + + /* Figure out which volume control button was pushed, + based on differences from the default register + values. */ + x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee; + + /* Reset the volume control registers. */ + outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE); + outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE); + outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); + outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER); + + if (!chip->master_switch || !chip->master_volume) + return; + + /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ + spin_lock_irqsave(&chip->ac97_lock, flags); + + val = chip->ac97->regs[AC97_MASTER_VOL]; + switch (x) { + case 0x88: + /* mute */ + val ^= 0x8000; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_switch->id); + break; + case 0xaa: + /* volume up */ + if ((val & 0x7f) > 0) + val--; + if ((val & 0x7f00) > 0) + val -= 0x0100; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); + break; + case 0x66: + /* volume down */ + if ((val & 0x7f) < 0x1f) + val++; + if ((val & 0x7f00) < 0x1f00) + val += 0x0100; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); + break; + } + spin_unlock_irqrestore(&chip->ac97_lock, flags); +} + static irqreturn_t snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -1576,7 +1643,10 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (status == 0xff) return IRQ_NONE; - + + if (status & HV_INT_PENDING) + tasklet_hi_schedule(&chip->hwvol_tq); + /* * ack an assp int if its running * and has an int pending @@ -1842,24 +1912,32 @@ static unsigned short snd_m3_ac97_read(ac97_t *ac97, unsigned short reg) { m3_t *chip = ac97->private_data; + unsigned long flags; + unsigned short data; if (snd_m3_ac97_wait(chip)) return 0xffff; + spin_lock_irqsave(&chip->ac97_lock, flags); snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); if (snd_m3_ac97_wait(chip)) return 0xffff; - return snd_m3_inw(chip, CODEC_DATA); + data = snd_m3_inw(chip, CODEC_DATA); + spin_unlock_irqrestore(&chip->ac97_lock, flags); + return data; } static void snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { m3_t *chip = ac97->private_data; + unsigned long flags; if (snd_m3_ac97_wait(chip)) return; + spin_lock_irqsave(&chip->ac97_lock, flags); snd_m3_outw(chip, val, CODEC_DATA); snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); + spin_unlock_irqrestore(&chip->ac97_lock, flags); } @@ -1968,6 +2046,7 @@ static int __devinit snd_m3_mixer(m3_t *chip) { ac97_bus_t *pbus; ac97_template_t ac97; + snd_ctl_elem_id_t id; int err; static ac97_bus_ops_t ops = { .write = snd_m3_ac97_write, @@ -1988,6 +2067,15 @@ static int __devinit snd_m3_mixer(m3_t *chip) schedule_timeout(HZ / 10); snd_ac97_write(chip->ac97, AC97_PCM, 0); + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, "Master Playback Switch"); + chip->master_switch = snd_ctl_find_id(chip->card, &id); + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, "Master Playback Volume"); + chip->master_volume = snd_ctl_find_id(chip->card, &id); + return 0; } @@ -2293,6 +2381,7 @@ static int snd_m3_chip_init(m3_t *chip) { struct pci_dev *pcidev = chip->pci; + unsigned long io = chip->iobase; u32 n; u16 w; u8 t; /* makes as much sense as 'n', no? */ @@ -2304,7 +2393,8 @@ snd_m3_chip_init(m3_t *chip) pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); - n &= REDUCED_DEBOUNCE; + n &= ~HV_BUTTON_FROM_GD; + n |= HV_CTRL_ENABLE | REDUCED_DEBOUNCE; n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); @@ -2332,6 +2422,12 @@ snd_m3_chip_init(m3_t *chip) outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); + outb(0x00, io + HARDWARE_VOL_CTRL); + outb(0x88, io + SHADOW_MIX_REG_VOICE); + outb(0x88, io + HW_VOL_COUNTER_VOICE); + outb(0x88, io + SHADOW_MIX_REG_MASTER); + outb(0x88, io + HW_VOL_COUNTER_MASTER); + return 0; } @@ -2341,7 +2437,7 @@ snd_m3_enable_ints(m3_t *chip) unsigned long io = chip->iobase; /* TODO: MPU401 not supported yet */ - outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); + outw(ASSP_INT_ENABLE | HV_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, io + ASSP_CONTROL_C); } @@ -2593,6 +2689,9 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, return err; } + spin_lock_init(&chip->ac97_lock); + tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); + if ((err = snd_m3_mixer(chip)) < 0) return err; -- cgit v0.10.2 From 091bf4dcab10b083f944d4eafbe0c734786485fe Mon Sep 17 00:00:00 2001 From: Ville Syrjala Date: Thu, 12 May 2005 14:20:57 +0200 Subject: [ALSA] maestro3: HP OmniBook HW volume button magic Maestro3 driver Some HP OmniBook laptops (500 and 6000 at least) require some GPIO magic before the HW volume buttons work. This patch makes them work mostly. Something is still missing to make them work perfectly. However I have been unable to figure out what exactly. Signed-off-by: Ville Syrjala Signed-off-by: Takashi Iwai diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index c1c7eee..3690ea0 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2392,6 +2392,18 @@ snd_m3_chip_init(m3_t *chip) DISABLE_LEGACY); pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); + /* + * Volume buttons on some HP OmniBook laptops (500 and 6000 at least) + * don't work correctly. This makes them work for the most part. + * Volume up and down buttons on the laptop side work perfectly. + * Fn+cursor_up (volme up) works, Fn+cursor_down (volume down) doesn't, + * Fn+F8 (mute) works acts as volume up. + */ + outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK); + outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION); + outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA); + outw(0xffff, io + GPIO_MASK); + pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); n &= ~HV_BUTTON_FROM_GD; n |= HV_CTRL_ENABLE | REDUCED_DEBOUNCE; -- cgit v0.10.2 From c74db86bcf0897cdd4dc1f85ae0d76ef59aaeb20 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 May 2005 14:26:27 +0200 Subject: [ALSA] Add position_fix module option Documentation,HDA Intel driver Added position_fix module option to HDA-intel driver for fixing up the DMA position (possibly hardware-) bugs. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index c69581c..ef07506 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -618,6 +618,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module for Intel HD Audio (ICH6, ICH6M, ICH7) model - force the model name + position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF) Module supports up to 8 cards. @@ -643,6 +644,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. full_dig 6-jack in back, 2-jack in front, SPDIF I/O allout 5-jack in back, 2-jack in front, SPDIF out + Note 2: If you get click noises on output, try the module option + position_fix=1 or 2. position_fix=1 will use the SD_LPIB + register value without FIFO size correction as the current + DMA pointer. position_fix=2 will make the driver to use + the position buffer instead of reading SD_LPIB register. + (Usually SD_LPLIB register is more accurate than the + position buffer.) + Module snd-hdsp --------------- diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cbc9ca7..104593f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -51,6 +51,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static char *model[SNDRV_CARDS]; +static int position_fix[SNDRV_CARDS]; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); @@ -60,6 +61,8 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); +module_param_array(position_fix, bool, NULL, 0444); +MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF)."); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," @@ -183,6 +186,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define ICH6_MAX_CORB_ENTRIES 256 #define ICH6_MAX_RIRB_ENTRIES 256 +/* position fix mode */ +enum { + POS_FIX_FIFO, + POS_FIX_NONE, + POS_FIX_POSBUF +}; /* * Use CORB/RIRB for communication from/to codecs. @@ -191,12 +200,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define USE_CORB_RIRB /* - * Define this if use the position buffer instead of reading SD_LPIB - * It's not used as default since SD_LPIB seems to give more accurate position - */ -/* #define USE_POSBUF */ - -/* */ typedef struct snd_azx azx_t; @@ -271,6 +274,9 @@ struct snd_azx { struct snd_dma_buffer bdl; struct snd_dma_buffer rb; struct snd_dma_buffer posbuf; + + /* flags */ + int position_fix; }; /* @@ -657,11 +663,11 @@ static void azx_init_chip(azx_t *chip) /* initialize the codec command I/O */ azx_init_cmd_io(chip); -#ifdef USE_POSBUF - /* program the position buffer */ - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); - azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); -#endif + if (chip->position_fix == POS_FIX_POSBUF) { + /* program the position buffer */ + azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); + azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); + } } @@ -791,11 +797,12 @@ static int azx_setup_controller(azx_t *chip, azx_dev_t *azx_dev) /* upper BDL address */ azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); -#ifdef USE_POSBUF - /* enable the position buffer */ - if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); -#endif + if (chip->position_fix == POS_FIX_POSBUF) { + /* enable the position buffer */ + if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); + } + /* set the interrupt enable bits in the descriptor control register */ azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); @@ -1036,16 +1043,20 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd) static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream) { + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + azx_t *chip = apcm->chip; azx_dev_t *azx_dev = get_azx_dev(substream); unsigned int pos; -#ifdef USE_POSBUF - /* use the position buffer */ - pos = *azx_dev->posbuf; -#else - /* read LPIB */ - pos = azx_sd_readl(azx_dev, SD_LPIB) + azx_dev->fifo_size; -#endif + if (chip->position_fix == POS_FIX_POSBUF) { + /* use the position buffer */ + pos = *azx_dev->posbuf; + } else { + /* read LPIB */ + pos = azx_sd_readl(azx_dev, SD_LPIB); + if (chip->position_fix == POS_FIX_FIFO) + pos += azx_dev->fifo_size; + } if (pos >= azx_dev->bufsize) pos = 0; return bytes_to_frames(substream->runtime, pos); @@ -1155,9 +1166,8 @@ static int __devinit azx_init_stream(azx_t *chip) azx_dev_t *azx_dev = &chip->azx_dev[i]; azx_dev->bdl = (u32 *)(chip->bdl.area + off); azx_dev->bdl_addr = chip->bdl.addr + off; -#ifdef USE_POSBUF - azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); -#endif + if (chip->position_fix == POS_FIX_POSBUF) + azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ @@ -1237,10 +1247,8 @@ static int azx_free(azx_t *chip) snd_dma_free_pages(&chip->bdl); if (chip->rb.area) snd_dma_free_pages(&chip->rb); -#ifdef USE_POSBUF if (chip->posbuf.area) snd_dma_free_pages(&chip->posbuf); -#endif pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); @@ -1256,7 +1264,8 @@ static int azx_dev_free(snd_device_t *device) /* * constructor */ -static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **rchip) +static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, + int posfix, azx_t **rchip) { azx_t *chip; int err = 0; @@ -1283,6 +1292,8 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r chip->pci = pci; chip->irq = -1; + chip->position_fix = posfix; + if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) { kfree(chip); pci_disable_device(pci); @@ -1314,14 +1325,14 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); goto errout; } -#ifdef USE_POSBUF - /* allocate memory for the position buffer */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) { - snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); - goto errout; + if (chip->position_fix == POS_FIX_POSBUF) { + /* allocate memory for the position buffer */ + if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) { + snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); + goto errout; + } } -#endif /* allocate CORB/RIRB */ if ((err = azx_alloc_cmd_io(chip)) < 0) goto errout; @@ -1372,7 +1383,7 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id * return -ENOMEM; } - if ((err = azx_create(card, pci, &chip)) < 0) { + if ((err = azx_create(card, pci, position_fix[dev], &chip)) < 0) { snd_card_free(card); return err; } -- cgit v0.10.2 From dfc0ff62a1d24e987205b41fbf322a4377626481 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 May 2005 14:31:49 +0200 Subject: [ALSA] Add ASUS Z71V support Documentation,HDA Codec driver Added the ASUS Z71V (or similar) laptop support. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index ef07506..d49325e 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -636,6 +636,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 5stack 5-jack in back, 2-jack in front 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out w810 3-jack + z71v 3-jack (HP shared SPDIF) CMI9880 minimal 3-jack in back diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 17c5062..c106e1f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -39,6 +39,7 @@ enum { ALC880_5ST, ALC880_5ST_DIG, ALC880_W810, + ALC880_Z71V, }; struct alc_spec { @@ -90,6 +91,11 @@ static hda_nid_t alc880_w810_dac_nids[3] = { 0x02, 0x03, 0x04 }; +static hda_nid_t alc880_z71v_dac_nids[1] = { + /* front only? */ + 0x02 +}; + static hda_nid_t alc880_adc_nids[3] = { /* ADC0-2 */ 0x07, 0x08, 0x09, @@ -284,6 +290,10 @@ static struct alc_channel_mode alc880_w810_modes[1] = { { 6, NULL } }; +static struct alc_channel_mode alc880_z71v_modes[1] = { + { 2, NULL } +}; + /* */ static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -475,6 +485,35 @@ static snd_kcontrol_new_t alc880_w810_base_mixer[] = { { } /* end */ }; +static snd_kcontrol_new_t alc880_z71v_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + /* */ static int alc_build_controls(struct hda_codec *codec) @@ -719,6 +758,58 @@ static struct hda_verb alc880_w810_init_verbs[] = { { } }; +static struct hda_verb alc880_z71v_init_verbs[] = { + /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, + /* front channel selector/amp: output 0: unmuted, max volume */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* front out pin: muted, (no volume selection) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* front out pin: NOT headphone enable, out enable, vref disabled */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* headphone channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* headphone channel selector/amp: input 1: capture mix: muted, (no volume selection) */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, + /* headphone channel selector/amp: output 0: unmuted, max volume */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* headphone out pin: muted, (no volume selection) */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* headpohne out pin: headphone enable, out enable, vref disabled */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* unmute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to line in (default select for this ADC) */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer + * widget(nid=0x0B) to support the input path of analog loopback + */ + /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ + /* unmute CD */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* unmute Line In */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + /* unmute Mic 1 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + /* unmute Line In 2 (for PASD boards Mic 2) */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + + { } +}; + static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -993,6 +1084,9 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .modelname = "w810", .config = ALC880_W810 }, { .pci_vendor = 0x161f, .pci_device = 0x203d, .config = ALC880_W810 }, + { .modelname = "z71v", .config = ALC880_Z71V }, + { .pci_vendor = 0x1043, .pci_device = 0x1964, .config = ALC880_Z71V }, + {} }; @@ -1023,6 +1117,10 @@ static int patch_alc880(struct hda_codec *codec) spec->mixers[spec->num_mixers] = alc880_five_stack_mixer; spec->num_mixers++; break; + case ALC880_Z71V: + spec->mixers[spec->num_mixers] = alc880_z71v_mixer; + spec->num_mixers++; + break; default: spec->mixers[spec->num_mixers] = alc880_base_mixer; spec->num_mixers++; @@ -1033,6 +1131,7 @@ static int patch_alc880(struct hda_codec *codec) case ALC880_3ST_DIG: case ALC880_5ST_DIG: case ALC880_W810: + case ALC880_Z71V: spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; break; default: @@ -1063,6 +1162,11 @@ static int patch_alc880(struct hda_codec *codec) spec->channel_mode = alc880_w810_modes; spec->num_channel_mode = ARRAY_SIZE(alc880_w810_modes); break; + case ALC880_Z71V: + spec->init_verbs = alc880_z71v_init_verbs; + spec->channel_mode = alc880_z71v_modes; + spec->num_channel_mode = ARRAY_SIZE(alc880_z71v_modes); + break; default: spec->init_verbs = alc880_init_verbs_three_stack; spec->channel_mode = alc880_threestack_modes; @@ -1086,6 +1190,11 @@ static int patch_alc880(struct hda_codec *codec) spec->multiout.dac_nids = alc880_w810_dac_nids; // No dedicated headphone socket - it's shared with built-in speakers. break; + case ALC880_Z71V: + spec->multiout.num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids); + spec->multiout.dac_nids = alc880_z71v_dac_nids; + spec->multiout.hp_nid = 0x03; + break; default: spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids); spec->multiout.dac_nids = alc880_dac_nids; -- cgit v0.10.2 From 2fa522bed875cf0bde9e9fdb8fdd852c9d74d67d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 May 2005 14:51:12 +0200 Subject: [ALSA] Add test model for debugging ALC880 devices HDA Codec driver Added 'test' model for testing/debugging the devices with ALC880 codec. This model is built only when CONFIG_SND_DEBUG is set. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c106e1f..75ec197 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -40,6 +40,7 @@ enum { ALC880_5ST_DIG, ALC880_W810, ALC880_Z71V, + ALC880_TEST, }; struct alc_spec { @@ -1012,6 +1013,248 @@ static struct hda_codec_ops alc_patch_ops = { #endif }; + +/* + * Test configuration for debugging + * + * Almost all inputs/outputs are enabled. I/O pins can be configured via + * enum controls. + */ +#ifdef CONFIG_SND_DEBUG +static hda_nid_t alc880_test_dac_nids[4] = { + 0x02, 0x03, 0x04, 0x05 +}; + +static struct hda_input_mux alc880_test_capture_source = { + .num_items = 5, + .items = { + { "In-1", 0x0 }, + { "In-2", 0x1 }, + { "In-3", 0x2 }, + { "In-4", 0x3 }, + { "CD", 0x4 }, + }, +}; + +static struct alc_channel_mode alc880_test_modes[2] = { + { 2, NULL }, + { 6, NULL }, +}; + +static int alc_test_pin_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[] = { + "N/A", "Line Out", "HP Out", + "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 8; + if (uinfo->value.enumerated.item >= 8) + uinfo->value.enumerated.item = 7; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_test_pin_ctl_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int pin_ctl, item = 0; + + pin_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (pin_ctl & AC_PINCTL_OUT_EN) { + if (pin_ctl & AC_PINCTL_HP_EN) + item = 2; + else + item = 1; + } else if (pin_ctl & AC_PINCTL_IN_EN) { + switch (pin_ctl & AC_PINCTL_VREFEN) { + case AC_PINCTL_VREF_HIZ: item = 3; break; + case AC_PINCTL_VREF_50: item = 4; break; + case AC_PINCTL_VREF_GRD: item = 5; break; + case AC_PINCTL_VREF_80: item = 6; break; + case AC_PINCTL_VREF_100: item = 7; break; + } + } + ucontrol->value.enumerated.item[0] = item; + return 0; +} + +static int alc_test_pin_ctl_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + static unsigned int ctls[] = { + 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, + }; + unsigned int old_ctl, new_ctl; + + old_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + new_ctl = ctls[ucontrol->value.enumerated.item[0]]; + if (old_ctl != new_ctl) { + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000); + return 1; + } + return 0; +} + +static int alc_test_pin_src_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[] = { + "Front", "Surround", "CLFE", "Side" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item >= 4) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_test_pin_src_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int sel; + + sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); + ucontrol->value.enumerated.item[0] = sel & 3; + return 0; +} + +static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int sel; + + sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; + if (ucontrol->value.enumerated.item[0] != sel) { + sel = ucontrol->value.enumerated.item[0] & 3; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); + return 1; + } + return 0; +} + +#define PIN_CTL_TEST(xname,nid) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = alc_test_pin_ctl_info, \ + .get = alc_test_pin_ctl_get, \ + .put = alc_test_pin_ctl_put, \ + .private_value = nid \ + } + +#define PIN_SRC_TEST(xname,nid) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = alc_test_pin_src_info, \ + .get = alc_test_pin_src_get, \ + .put = alc_test_pin_src_put, \ + .private_value = nid \ + } + +static snd_kcontrol_new_t alc880_test_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + PIN_CTL_TEST("Front Pin Mode", 0x14), + PIN_CTL_TEST("Surround Pin Mode", 0x15), + PIN_CTL_TEST("CLFE Pin Mode", 0x16), + PIN_CTL_TEST("Side Pin Mode", 0x17), + PIN_CTL_TEST("In-1 Pin Mode", 0x18), + PIN_CTL_TEST("In-2 Pin Mode", 0x19), + PIN_CTL_TEST("In-3 Pin Mode", 0x1a), + PIN_CTL_TEST("In-4 Pin Mode", 0x1b), + PIN_SRC_TEST("In-1 Pin Source", 0x18), + PIN_SRC_TEST("In-2 Pin Source", 0x19), + PIN_SRC_TEST("In-3 Pin Source", 0x1a), + PIN_SRC_TEST("In-4 Pin Source", 0x1b), + HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc880_ch_mode_info, + .get = alc880_ch_mode_get, + .put = alc880_ch_mode_put, + }, + { } /* end */ +}; + +static struct hda_verb alc880_test_init_verbs[] = { + /* Unmute inputs of 0x0c - 0x0f */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, + /* Vol output for 0x0c-0x0f */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* Set output pins 0x14-0x17 */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Unmute output pins 0x14-0x17 */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Set input pins 0x18-0x1c */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* vref 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* Mute input pins 0x18-0x1b */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + { } +}; +#endif + /* */ @@ -1087,6 +1330,10 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .modelname = "z71v", .config = ALC880_Z71V }, { .pci_vendor = 0x1043, .pci_device = 0x1964, .config = ALC880_Z71V }, +#ifdef CONFIG_SND_DEBUG + { .modelname = "test", .config = ALC880_TEST }, +#endif + {} }; @@ -1121,6 +1368,12 @@ static int patch_alc880(struct hda_codec *codec) spec->mixers[spec->num_mixers] = alc880_z71v_mixer; spec->num_mixers++; break; +#ifdef CONFIG_SND_DEBUG + case ALC880_TEST: + spec->mixers[spec->num_mixers] = alc880_test_mixer; + spec->num_mixers++; + break; +#endif default: spec->mixers[spec->num_mixers] = alc880_base_mixer; spec->num_mixers++; @@ -1132,6 +1385,7 @@ static int patch_alc880(struct hda_codec *codec) case ALC880_5ST_DIG: case ALC880_W810: case ALC880_Z71V: + case ALC880_TEST: spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; break; default: @@ -1167,6 +1421,13 @@ static int patch_alc880(struct hda_codec *codec) spec->channel_mode = alc880_z71v_modes; spec->num_channel_mode = ARRAY_SIZE(alc880_z71v_modes); break; +#ifdef CONFIG_SND_DEBUG + case ALC880_TEST: + spec->init_verbs = alc880_test_init_verbs; + spec->channel_mode = alc880_test_modes; + spec->num_channel_mode = ARRAY_SIZE(alc880_test_modes); + break; +#endif default: spec->init_verbs = alc880_init_verbs_three_stack; spec->channel_mode = alc880_threestack_modes; @@ -1195,6 +1456,13 @@ static int patch_alc880(struct hda_codec *codec) spec->multiout.dac_nids = alc880_z71v_dac_nids; spec->multiout.hp_nid = 0x03; break; +#ifdef CONFIG_SND_DEBUG + case ALC880_TEST: + spec->multiout.num_dacs = ARRAY_SIZE(alc880_test_dac_nids); + spec->multiout.dac_nids = alc880_test_dac_nids; + spec->input_mux = &alc880_test_capture_source; + break; +#endif default: spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids); spec->multiout.dac_nids = alc880_dac_nids; @@ -1202,7 +1470,8 @@ static int patch_alc880(struct hda_codec *codec) break; } - spec->input_mux = &alc880_capture_source; + if (! spec->input_mux) + spec->input_mux = &alc880_capture_source; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); spec->adc_nids = alc880_adc_nids; -- cgit v0.10.2 From f5d40b30ed4daf09f1d43f9b2da1263b17a53c28 Mon Sep 17 00:00:00 2001 From: Frederick Li Date: Thu, 12 May 2005 14:55:20 +0200 Subject: [ALSA] Adding support for ATI IXP450 HD Audio device support Documentation,HDA Intel driver This patch changes the Intel HD Audio device driver to include the support of HD Audio device embedded in ATI south bridge IXP450. Because the design of ATI chipset follows intel HD Audio specification 1.0, the programming method is the same as that of intel HD Audio device exception one minor change which requires to enable snoop for DMA transport. There are 3 changes that have been made to hda_intel.c file. 1. Added device ID for ATI HD Audio device; 2. Increase maximum CODEC supported to 4; 3. Enable snoop during the driver initialization. Signed-off-by: Frederick Li Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index d49325e..587eddc 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -615,7 +615,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module snd-hda-intel -------------------- - Module for Intel HD Audio (ICH6, ICH6M, ICH7) + Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450 model - force the model name position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 104593f..d8329a7 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -68,7 +68,8 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH6M}," "{Intel, ICH7}," - "{Intel, ESB2}}"); + "{Intel, ESB2}," + "{ATI, SB450}}"); MODULE_DESCRIPTION("Intel HDA driver"); #define SFX "hda-intel: " @@ -153,7 +154,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* STATESTS int mask: SD2,SD1,SD0 */ #define STATESTS_INT_MASK 0x07 -#define AZX_MAX_CODECS 3 +#define AZX_MAX_CODECS 4 /* SD_CTL bits */ #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ @@ -193,6 +194,12 @@ enum { POS_FIX_POSBUF }; +/* Defines for ATI HD Audio support in SB450 south bridge */ +#define ATI_SB450_HDAUDIO_PCI_DEVICE_ID 0x437b +#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 +#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 + + /* * Use CORB/RIRB for communication from/to codecs. * This is the way recommended by Intel (see below). @@ -644,7 +651,7 @@ static void azx_stream_stop(azx_t *chip, azx_dev_t *azx_dev) */ static void azx_init_chip(azx_t *chip) { - unsigned char tcsel_reg; + unsigned char tcsel_reg, ati_misc_cntl2; /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) * TCSEL == Traffic Class Select Register, which sets PCI express QOS @@ -668,6 +675,15 @@ static void azx_init_chip(azx_t *chip) azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); } + + /* For ATI SB450 azalia HD audio, we need to enable snoop */ + if (chip->pci->vendor == PCI_VENDOR_ID_ATI && + chip->pci->device == ATI_SB450_HDAUDIO_PCI_DEVICE_ID) { + pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, + &ati_misc_cntl2); + pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, + (ati_misc_cntl2 & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP); + } } @@ -1435,6 +1451,7 @@ static struct pci_device_id azx_ids[] = { { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */ { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */ { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ + { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); -- cgit v0.10.2 From fc20a562ca1a3c22dc257b2e2d849cb1a9ab6420 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 May 2005 15:00:41 +0200 Subject: [ALSA] Add support of VIA VT8251/VT8237A HD-Audio controllers Documentation,HDA Intel driver Added the support of VIA VT8251/VT8237A HD-Audio controllers. They are (almost) compatible with Intel ICH6/7. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 587eddc..5a7f7f5 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -615,7 +615,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module snd-hda-intel -------------------- - Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450 + Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450, + VIA VT8251/VT8237A model - force the model name position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d8329a7..87988da 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -69,7 +69,9 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH6M}," "{Intel, ICH7}," "{Intel, ESB2}," - "{ATI, SB450}}"); + "{ATI, SB450}," + "{VIA, VT8251}," + "{VIA, VT8237A}}"); MODULE_DESCRIPTION("Intel HDA driver"); #define SFX "hda-intel: " @@ -1452,6 +1454,7 @@ static struct pci_device_id azx_ids[] = { { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */ { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */ + { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); -- cgit v0.10.2 From 7291548df69ab4e3a87ff6952449d1f05c3a5443 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 May 2005 16:49:45 +0200 Subject: [ALSA] Rename pci_vendor/pci_device to pci_subvendor/pci_subdevice HDA Codec driver,HDA generic driver Renamed pci_vendor/pci_device fields to pci_subvendor/pci_subdevice. They are really PCI subsystem IDs. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 44fac21..87018df 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1530,7 +1530,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config struct hda_board_config *c; if (codec->bus->modelname) { - for (c = tbl; c->modelname || c->pci_vendor; c++) { + for (c = tbl; c->modelname || c->pci_subvendor; c++) { if (c->modelname && ! strcmp(codec->bus->modelname, c->modelname)) { snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname); @@ -1543,9 +1543,9 @@ int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config u16 subsystem_vendor, subsystem_device; pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device); - for (c = tbl; c->modelname || c->pci_vendor; c++) { - if (c->pci_vendor == subsystem_vendor && - c->pci_device == subsystem_device) + for (c = tbl; c->modelname || c->pci_subvendor; c++) { + if (c->pci_subvendor == subsystem_vendor && + c->pci_subdevice == subsystem_device) return c->config; } } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7c7b849..b8fbbc4 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -126,8 +126,8 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } struct hda_board_config { const char *modelname; int config; - unsigned short pci_vendor; - unsigned short pci_device; + unsigned short pci_subvendor; + unsigned short pci_subdevice; }; int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 75ec197..8a10482 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1261,74 +1261,74 @@ static struct hda_verb alc880_test_init_verbs[] = { static struct hda_board_config alc880_cfg_tbl[] = { /* Back 3 jack, front 2 jack */ { .modelname = "3stack", .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe200, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe201, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe202, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe203, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe204, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe205, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe206, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe207, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe208, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe209, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20a, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20b, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20c, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20d, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20e, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20f, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe210, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe211, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe214, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe302, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe303, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe304, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe306, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe307, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe404, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xa101, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x3031, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4036, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4037, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4038, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4040, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4041, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, /* Back 3 jack, front 2 jack (Internal add Aux-In) */ - { .pci_vendor = 0x1025, .pci_device = 0xe310, .config = ALC880_3ST }, + { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xe308, .config = ALC880_3ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ - { .pci_vendor = 0x8086, .pci_device = 0xe305, .config = ALC880_3ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xd402, .config = ALC880_3ST_DIG }, - { .pci_vendor = 0x1025, .pci_device = 0xe309, .config = ALC880_3ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG }, + { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG }, /* Back 5 jack, front 2 jack */ { .modelname = "5stack", .config = ALC880_5ST }, - { .pci_vendor = 0x107b, .pci_device = 0x3033, .config = ALC880_5ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4039, .config = ALC880_5ST }, - { .pci_vendor = 0x107b, .pci_device = 0x3032, .config = ALC880_5ST }, - { .pci_vendor = 0x103c, .pci_device = 0x2a09, .config = ALC880_5ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST }, + { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST }, /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xe224, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xe400, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xe401, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xe402, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xd400, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xd401, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xa100, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x1565, .pci_device = 0x8202, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, { .modelname = "w810", .config = ALC880_W810 }, - { .pci_vendor = 0x161f, .pci_device = 0x203d, .config = ALC880_W810 }, + { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 }, { .modelname = "z71v", .config = ALC880_Z71V }, - { .pci_vendor = 0x1043, .pci_device = 0x1964, .config = ALC880_Z71V }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, #ifdef CONFIG_SND_DEBUG { .modelname = "test", .config = ALC880_TEST }, -- cgit v0.10.2 From 50cdbf1519a891bec4ce306c7bae397a0d8e7246 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 13 May 2005 07:44:13 +0200 Subject: [ALSA] usb-audio - sanity-check sync feedback frequency values USB generic driver Check that the synchronization feedback frequency values returned by the device are more or less near the nominal frequency. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index c360ab9..a6ed0d0 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -452,17 +452,11 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, if (urb->iso_frame_desc[0].status == 0 && urb->iso_frame_desc[0].actual_length == 3) { f = combine_triple((u8*)urb->transfer_buffer) << 2; -#if 0 - if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) { - snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n", - f, f >> 14, (f & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1), - subs->freqn, subs->freqn >> 14, (subs->freqn & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1)); - continue; + if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); } -#endif - spin_lock_irqsave(&subs->lock, flags); - subs->freqm = f; - spin_unlock_irqrestore(&subs->lock, flags); } return 0; @@ -484,9 +478,11 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, if (urb->iso_frame_desc[0].status == 0 && urb->iso_frame_desc[0].actual_length == 4) { f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; - spin_lock_irqsave(&subs->lock, flags); - subs->freqm = f; - spin_unlock_irqrestore(&subs->lock, flags); + if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); + } } return 0; -- cgit v0.10.2 From 29b16931f936fdbcd78995e66d0f5626f3afbda8 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 13 May 2005 07:50:28 +0200 Subject: [ALSA] usb-audio - avoid unnecessary double buffering USB generic driver When a USB packet boundary falls exactly on a buffer boundary, hwptr remains at the end of the buffer which causes an overflow in the next iteration and triggers double buffering although the next packet would actually be contiguous. This patch ensures that hwptr is always smaller than buffer_size. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a6ed0d0..076da19 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -565,6 +565,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, /* set the buffer pointer */ urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride; subs->hwptr += offs; + if (subs->hwptr == runtime->buffer_size) + subs->hwptr = 0; } spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = offs * stride; -- cgit v0.10.2 From 10268b0c38333ede95bb59a7fa561519e6eb8251 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 May 2005 11:01:13 +0200 Subject: [ALSA] Remove obsolete mixer control AC97 Codec Removed the obsolete mixer control for AD1985. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index ce02e70..bcb1a20 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1598,7 +1598,6 @@ int patch_ad1980(ac97_t * ac97) } static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { - AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0), AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) }; -- cgit v0.10.2 From 89c87bf8c12e27fbbed971380e21895cace3a065 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 13 May 2005 15:28:08 +0200 Subject: [ALSA] make code static CA0106 driver,HDA Codec driver This patch makes needlessly global code static. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 0bc1d78..3e5161a 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -95,7 +95,7 @@ static struct snd_ca0106_category_str snd_ca0106_con_category[] = { }; -void snd_ca0106_proc_dump_iec958( snd_info_buffer_t *buffer, u32 value) +static void snd_ca0106_proc_dump_iec958( snd_info_buffer_t *buffer, u32 value) { int i; u32 status[4]; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 87018df..70e3cb6 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -662,7 +662,7 @@ static void put_vol_mute(struct hda_codec *codec, /* * read/write AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. */ -int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) +static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) { struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); if (! info) @@ -671,7 +671,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int d return info->vol[ch]; } -int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val) +static int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val) { struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); if (! info) -- cgit v0.10.2 From 680ff0ac6d0c84f14a2e540f64521a9fa80d8661 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 May 2005 16:06:14 +0200 Subject: [ALSA] Suppress error message HDA Codec driver Suppressing the error message regarding no AFG. This is often harmless (e.g. probing a modem codec). Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 70e3cb6..56941031 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -509,7 +509,7 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, /* FIXME: support for multiple AFGs? */ codec->afg = look_for_afg_node(codec); if (! codec->afg) { - snd_printk(KERN_ERR "hda_codec: no AFG node found\n"); + snd_printdd("hda_codec: no AFG node found\n"); snd_hda_codec_free(codec); return -ENODEV; } -- cgit v0.10.2 From 9bc533f58e8515cf346932fc84a58dd706342635 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 May 2005 16:44:27 +0200 Subject: [ALSA] Fix a typo in position_fix module option type HDA Intel driver Fixed a typo in the type of position_fix module option. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 87988da..f05a638 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -61,7 +61,7 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); -module_param_array(position_fix, bool, NULL, 0444); +module_param_array(position_fix, int, NULL, 0444); MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF)."); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From fd2c326de8cd35a36514a887541426b1ef7c5516 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 May 2005 17:18:42 +0200 Subject: [ALSA] Allow more than 2 channel modes HDA Codec driver Allow 'Channel Mode' control to have more than 2 modes. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8a10482..9f12d1f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -301,13 +301,14 @@ static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *ui { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; + int items = kcontrol->private_value ? (int)kcontrol->private_value : 2; snd_assert(spec->channel_mode, return -ENXIO); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; + uinfo->value.enumerated.items = items; + if (uinfo->value.enumerated.item >= items) + uinfo->value.enumerated.item = items - 1; sprintf(uinfo->value.enumerated.name, "%dch", spec->channel_mode[uinfo->value.enumerated.item].channels); return 0; @@ -317,10 +318,16 @@ static int alc880_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; + int items = kcontrol->private_value ? (int)kcontrol->private_value : 2; + int i; snd_assert(spec->channel_mode, return -ENXIO); - ucontrol->value.enumerated.item[0] = - (spec->multiout.max_channels == spec->channel_mode[0].channels) ? 0 : 1; + for (i = 0; i < items; i++) { + if (spec->multiout.max_channels == spec->channel_mode[i].channels) { + ucontrol->value.enumerated.item[0] = i; + break; + } + } return 0; } @@ -1036,9 +1043,11 @@ static struct hda_input_mux alc880_test_capture_source = { }, }; -static struct alc_channel_mode alc880_test_modes[2] = { +static struct alc_channel_mode alc880_test_modes[4] = { { 2, NULL }, + { 4, NULL }, { 6, NULL }, + { 8, NULL }, }; static int alc_test_pin_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -1211,6 +1220,7 @@ static snd_kcontrol_new_t alc880_test_mixer[] = { .info = alc880_ch_mode_info, .get = alc880_ch_mode_get, .put = alc880_ch_mode_put, + .private_value = ARRAY_SIZE(alc880_test_modes), }, { } /* end */ }; -- cgit v0.10.2 From 54b903ec6e5a3194d86d8bb2f419c918efa4897f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 15 May 2005 14:30:10 +0200 Subject: [ALSA] Add Analog Devices vendor name HDA Codec driver Added the missing vendor name entry for Analog Devices. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 56941031..e6efaed 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -49,6 +49,7 @@ struct hda_vendor_id { /* codec vendor labels */ static struct hda_vendor_id hda_vendor_ids[] = { { 0x10ec, "Realtek" }, + { 0x11d4, "Analog Devices" }, { 0x13f6, "C-Media" }, { 0x434d, "C-Media" }, { 0x8384, "SigmaTel" }, -- cgit v0.10.2 From 6d85be612d8b6a6730d19e742329e5ffa60eafdd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 15 May 2005 14:32:50 +0200 Subject: [ALSA] Suppress debug message Control Midlevel Suppress 'unknown ioctl' debug message (replaced with snd_printdd). Signed-off-by: Takashi Iwai diff --git a/sound/core/control.c b/sound/core/control.c index f4ea6bf..4e39a21 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1102,7 +1102,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg } } up_read(&snd_ioctl_rwsem); - snd_printd("unknown ioctl = 0x%x\n", cmd); + snd_printdd("unknown ioctl = 0x%x\n", cmd); return -ENOTTY; } -- cgit v0.10.2 From 92bb010cd874e53e4c2e2a73510966e45cfa4525 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 15 May 2005 14:41:20 +0200 Subject: [ALSA] Add PnP ID ADS7180 AD1816A driver Added PnP ID 'ADS7180' (AD1816?). Signed-off-by: Takashi Iwai diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index 9fa7a78..563296d 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -83,6 +83,8 @@ struct snd_card_ad1816a { static struct pnp_card_device_id snd_ad1816a_pnpids[] = { /* Analog Devices AD1815 */ { .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } }, + /* Analog Device AD1816? */ + { .id = "ADS7180", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, /* Analog Devices AD1816A - added by Kenneth Platz */ { .id = "ADS7181", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, /* Analog Devices AD1816A - Aztech/Newcom SC-16 3D */ -- cgit v0.10.2 From 15790a6be14852850ee7cbd791225fa51750d8af Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 15 May 2005 15:04:14 +0200 Subject: [ALSA] Add missing PAUSE ioctl Timer Midlevel Added the missing implemenation of TIMER PAUSE ioctl. Signed-off-by: Takashi Iwai diff --git a/sound/core/timer.c b/sound/core/timer.c index be6d37a..48aebdf 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1680,6 +1680,16 @@ static int snd_timer_user_continue(struct file *file) return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; } +static int snd_timer_user_pause(struct file *file) +{ + int err; + snd_timer_user_t *tu; + + tu = file->private_data; + snd_assert(tu->timeri != NULL, return -ENXIO); + return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; +} + static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { snd_timer_user_t *tu; @@ -1729,6 +1739,8 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l return snd_timer_user_stop(file); case SNDRV_TIMER_IOCTL_CONTINUE: return snd_timer_user_continue(file); + case SNDRV_TIMER_IOCTL_PAUSE: + return snd_timer_user_pause(file); } return -ENOTTY; } diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index 9fbc395..420817d 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c @@ -108,6 +108,7 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns case SNDRV_TIMER_IOCTL_START: case SNDRV_TIMER_IOCTL_STOP: case SNDRV_TIMER_IOCTL_CONTINUE: + case SNDRV_TIMER_IOCTL_PAUSE: case SNDRV_TIMER_IOCTL_NEXT_DEVICE: return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); case SNDRV_TIMER_IOCTL_INFO32: -- cgit v0.10.2 From 8c50b37c04a026ab6641ecb7eaf0fd479798e8b8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 15 May 2005 15:43:54 +0200 Subject: [ALSA] Change some timer ioctls due to confliction Timer Midlevel,ALSA Core Change values of some timer ioctls to avoid confliction with FIO* ioctls. The protocol version is increased to indicate this change. Signed-off-by: Takashi Iwai diff --git a/include/sound/asound.h b/include/sound/asound.h index 4321e92..9974f83 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -560,7 +560,7 @@ enum { * Timer section - /dev/snd/timer */ -#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 3) +#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4) enum sndrv_timer_class { SNDRV_TIMER_CLASS_NONE = -1, @@ -673,10 +673,11 @@ enum { SNDRV_TIMER_IOCTL_INFO = _IOR('T', 0x11, struct sndrv_timer_info), SNDRV_TIMER_IOCTL_PARAMS = _IOW('T', 0x12, struct sndrv_timer_params), SNDRV_TIMER_IOCTL_STATUS = _IOR('T', 0x14, struct sndrv_timer_status), - SNDRV_TIMER_IOCTL_START = _IO('T', 0x20), - SNDRV_TIMER_IOCTL_STOP = _IO('T', 0x21), - SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0x22), - SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0x23), + /* The following four ioctls are changed since 1.0.9 due to confliction */ + SNDRV_TIMER_IOCTL_START = _IO('T', 0xa0), + SNDRV_TIMER_IOCTL_STOP = _IO('T', 0xa1), + SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0xa2), + SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0xa3), }; struct sndrv_timer_read { diff --git a/sound/core/timer.c b/sound/core/timer.c index 48aebdf..305e39d 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1690,6 +1690,13 @@ static int snd_timer_user_pause(struct file *file) return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; } +enum { + SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20), + SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21), + SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22), + SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), +}; + static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { snd_timer_user_t *tu; @@ -1734,12 +1741,16 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l case SNDRV_TIMER_IOCTL_STATUS: return snd_timer_user_status(file, argp); case SNDRV_TIMER_IOCTL_START: + case SNDRV_TIMER_IOCTL_START_OLD: return snd_timer_user_start(file); case SNDRV_TIMER_IOCTL_STOP: + case SNDRV_TIMER_IOCTL_STOP_OLD: return snd_timer_user_stop(file); case SNDRV_TIMER_IOCTL_CONTINUE: + case SNDRV_TIMER_IOCTL_CONTINUE_OLD: return snd_timer_user_continue(file); case SNDRV_TIMER_IOCTL_PAUSE: + case SNDRV_TIMER_IOCTL_PAUSE_OLD: return snd_timer_user_pause(file); } return -ENOTTY; diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index 420817d..3de552d 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c @@ -106,9 +106,13 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns case SNDRV_TIMER_IOCTL_SELECT: case SNDRV_TIMER_IOCTL_PARAMS: case SNDRV_TIMER_IOCTL_START: + case SNDRV_TIMER_IOCTL_START_OLD: case SNDRV_TIMER_IOCTL_STOP: + case SNDRV_TIMER_IOCTL_STOP_OLD: case SNDRV_TIMER_IOCTL_CONTINUE: + case SNDRV_TIMER_IOCTL_CONTINUE_OLD: case SNDRV_TIMER_IOCTL_PAUSE: + case SNDRV_TIMER_IOCTL_PAUSE_OLD: case SNDRV_TIMER_IOCTL_NEXT_DEVICE: return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); case SNDRV_TIMER_IOCTL_INFO32: -- cgit v0.10.2 From d138b44589cc180418f5a20cb0ecfe338123d86c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 16 May 2005 13:51:39 +0200 Subject: [ALSA] fixed PAUSE ioctl for user space interface Timer Midlevel - fixed traditional cut-n-paste error Signed-off-by: Jaroslav Kysela diff --git a/sound/core/timer.c b/sound/core/timer.c index 305e39d..cb011a1 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1687,7 +1687,7 @@ static int snd_timer_user_pause(struct file *file) tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); - return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; + return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0; } enum { -- cgit v0.10.2 From d3ff42fd2b4fddb5d779e9e03a2ea44147aa8048 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 17 May 2005 09:14:27 +0200 Subject: [ALSA] usb-audio - claim all interfaces for Roland USB MIDI devices USB generic driver Many Roland USB MIDI devices have two interfaces that are currently not used by the driver; claim them anyway. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 00781fe..f513564 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -203,11 +203,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "UM-4", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x000f, - .in_cables = 0x000f + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x000f, + .in_cables = 0x000f + } + }, + { + .ifnum = -1 + } } } }, @@ -216,11 +233,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "SC-8850", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x003f, - .in_cables = 0x003f + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x003f, + .in_cables = 0x003f + } + }, + { + .ifnum = -1 + } } } }, @@ -229,11 +263,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "U-8", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0005, - .in_cables = 0x0005 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0005, + .in_cables = 0x0005 + } + }, + { + .ifnum = -1 + } } } }, @@ -242,11 +293,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "UM-2", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0003, - .in_cables = 0x0003 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } + }, + { + .ifnum = -1 + } } } }, @@ -255,11 +323,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "SC-8820", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0013, - .in_cables = 0x0013 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0013, + .in_cables = 0x0013 + } + }, + { + .ifnum = -1 + } } } }, @@ -268,11 +353,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "PC-300", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0001, - .in_cables = 0x0001 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } } } }, @@ -281,11 +383,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "UM-1", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0001, - .in_cables = 0x0001 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } } } }, @@ -294,11 +413,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "SK-500", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0013, - .in_cables = 0x0013 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0013, + .in_cables = 0x0013 + } + }, + { + .ifnum = -1 + } } } }, @@ -421,11 +557,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "SD-90", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x000f, - .in_cables = 0x000f + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x000f, + .in_cables = 0x000f + } + }, + { + .ifnum = -1 + } } } }, @@ -434,11 +587,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "MMP-2", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0001, - .in_cables = 0x0001 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } } } }, -- cgit v0.10.2 From 604cf499256af85703bd4858da56e777ec71714d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 17 May 2005 09:15:27 +0200 Subject: [ALSA] usb-audio - fix synchronization packet interval with Audigy 2 NX USB generic driver When a device does not provide the bRefresh field in its audio endpoint descriptors, use the bInterval field instead. Furthermore, increase the number of sync URBs for better queueing. Signed-off-by: Clemens Ladisch diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 076da19..a82412b 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -98,7 +98,7 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); #define MAX_PACKS 10 #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ #define MAX_URBS 5 /* max. 20ms long packets */ -#define SYNC_URBS 2 /* always two urbs for sync */ +#define SYNC_URBS 4 /* always four urbs for sync */ #define MIN_PACKS_URB 1 /* minimum 1 packet per urb */ typedef struct snd_usb_substream snd_usb_substream_t; @@ -1240,8 +1240,13 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) get_endpoint(alts, 1)->bRefresh >= 1 && get_endpoint(alts, 1)->bRefresh <= 9) subs->syncinterval = get_endpoint(alts, 1)->bRefresh; - else + else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) subs->syncinterval = 1; + else if (get_endpoint(alts, 1)->bInterval >= 1 && + get_endpoint(alts, 1)->bInterval <= 16) + subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1; + else + subs->syncinterval = 3; } /* always fill max packet size */ -- cgit v0.10.2 From e5b3f45f5d442b57dd07dd4f914f7e6cf4d183f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 May 2005 17:17:57 +0200 Subject: [ALSA] Fix Mic/CLFE sharing on AD1985 AC97 Codec Fixed Mic/CLFE jack sharing on AD1985 codec. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index bcb1a20..5520f5d 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1526,13 +1526,8 @@ static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { .get = snd_ac97_ad1888_downmix_get, .put = snd_ac97_ad1888_downmix_put }, -#if 0 - AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), - AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), -#else AC97_SURROUND_JACK_MODE_CTL, AC97_CHANNEL_MODE_CTL, -#endif }; static int patch_ad1888_specific(ac97_t *ac97) @@ -1601,6 +1596,18 @@ static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) }; +static void ad1985_update_jacks(ac97_t *ac97) +{ + /* shared Line-In */ + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, + is_shared_linein(ac97) ? 0 : 1 << 12); + /* shared Mic */ + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, + is_shared_micin(ac97) ? 0 : 1 << 11); + snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 9 << 11, + is_shared_micin(ac97) ? 0 : 9 << 11); +} + static int patch_ad1985_specific(ac97_t *ac97) { int err; @@ -1616,7 +1623,7 @@ static struct snd_ac97_build_ops patch_ad1985_build_ops = { #ifdef CONFIG_PM .resume = ad18xx_resume, #endif - .update_jacks = ad1888_update_jacks, + .update_jacks = ad1985_update_jacks, }; int patch_ad1985(ac97_t * ac97) -- cgit v0.10.2 From 9502dcad6c1138a3ce2bae23ccd4be44c718d2a9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 18 May 2005 16:25:46 +0200 Subject: [ALSA] Export missing snd_pcm_format_*() PCM Midlevel Export snd_pcm_format_size(). This function is used by some out-of-kernel drivers. Make snd_pcm_format_cpu_endian() macro for optimization. Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 53fc04d..50a6ee1 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -922,8 +922,22 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format); int snd_pcm_format_linear(snd_pcm_format_t format); int snd_pcm_format_little_endian(snd_pcm_format_t format); int snd_pcm_format_big_endian(snd_pcm_format_t format); +/** + * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian + * @format: the format to check + * + * Returns 1 if the given PCM format is CPU-endian, 0 if + * opposite, or a negative error code if endian not specified. + */ +/* int snd_pcm_format_cpu_endian(snd_pcm_format_t format); */ +#ifdef SNDRV_LITTLE_ENDIAN +#define snd_pcm_format_cpu_endian snd_pcm_format_little_endian +#else +#define snd_pcm_format_cpu_endian snd_pcm_format_big_endian +#endif int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */ int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ +ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples); const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format); int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames); snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian); diff --git a/sound/core/pcm.c b/sound/core/pcm.c index a2757fc..d57f4ec 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1069,6 +1069,7 @@ EXPORT_SYMBOL(snd_pcm_format_little_endian); EXPORT_SYMBOL(snd_pcm_format_big_endian); EXPORT_SYMBOL(snd_pcm_format_width); EXPORT_SYMBOL(snd_pcm_format_physical_width); +EXPORT_SYMBOL(snd_pcm_format_size); EXPORT_SYMBOL(snd_pcm_format_silence_64); EXPORT_SYMBOL(snd_pcm_format_set_silence); EXPORT_SYMBOL(snd_pcm_build_linear_format); diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 422b8db..1453743 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -270,22 +270,6 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format) } /** - * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian - * @format: the format to check - * - * Returns 1 if the given PCM format is CPU-endian, 0 if - * opposite, or a negative error code if endian not specified. - */ -int snd_pcm_format_cpu_endian(snd_pcm_format_t format) -{ -#ifdef SNDRV_LITTLE_ENDIAN - return snd_pcm_format_little_endian(format); -#else - return snd_pcm_format_big_endian(format); -#endif -} - -/** * snd_pcm_format_width - return the bit-width of the format * @format: the format to check * -- cgit v0.10.2 From 5218064c885af5c49e380d09d54f3cc86891a580 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 18 May 2005 16:31:51 +0200 Subject: [ALSA] ppc32: Fix Alsa PowerMac driver on old machines PPC PMAC driver The g5 support code broke some earlier models unfortunately as those bail out early from the detect function, before the point where I added the code to locate the PCI device for use with DMA allocations. This patch fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Takashi Iwai diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 32d9475..080ef39 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -876,7 +876,7 @@ static void __init detect_byte_swap(pmac_t *chip) */ static int __init snd_pmac_detect(pmac_t *chip) { - struct device_node *sound; + struct device_node *sound = NULL; unsigned int *prop, l; struct macio_chip* macio; @@ -906,20 +906,22 @@ static int __init snd_pmac_detect(pmac_t *chip) chip->is_pbook_G3 = 1; chip->node = find_devices("awacs"); if (chip->node) - return 0; /* ok */ + sound = chip->node; /* * powermac G3 models have a node called "davbus" * with a child called "sound". */ - chip->node = find_devices("davbus"); + if (!chip->node) + chip->node = find_devices("davbus"); /* * if we didn't find a davbus device, try 'i2s-a' since * this seems to be what iBooks have */ if (! chip->node) { chip->node = find_devices("i2s-a"); - if (chip->node && chip->node->parent && chip->node->parent->parent) { + if (chip->node && chip->node->parent && + chip->node->parent->parent) { if (device_is_compatible(chip->node->parent->parent, "K2-Keylargo")) chip->is_k2 = 1; @@ -928,9 +930,11 @@ static int __init snd_pmac_detect(pmac_t *chip) if (! chip->node) return -ENODEV; - sound = find_devices("sound"); - while (sound && sound->parent != chip->node) - sound = sound->next; + if (!sound) { + sound = find_devices("sound"); + while (sound && sound->parent != chip->node) + sound = sound->next; + } if (! sound) return -ENODEV; prop = (unsigned int *) get_property(sound, "sub-frame", NULL); @@ -1019,7 +1023,8 @@ static int __init snd_pmac_detect(pmac_t *chip) } } if (chip->pdev == NULL) - printk(KERN_WARNING "snd-powermac: can't locate macio PCI device !\n"); + printk(KERN_WARNING "snd-powermac: can't locate macio PCI" + " device !\n"); detect_byte_swap(chip); @@ -1027,7 +1032,8 @@ static int __init snd_pmac_detect(pmac_t *chip) are available */ prop = (unsigned int *) get_property(sound, "sample-rates", &l); if (! prop) - prop = (unsigned int *) get_property(sound, "output-frame-rates", &l); + prop = (unsigned int *) get_property(sound, + "output-frame-rates", &l); if (prop) { int i; chip->freqs_ok = 0; @@ -1054,7 +1060,8 @@ static int __init snd_pmac_detect(pmac_t *chip) /* * exported - boolean info callbacks for ease of programming */ -int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 2; @@ -1063,7 +1070,8 @@ int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * return 0; } -int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; -- cgit v0.10.2 From 123992f728785e05f385d23893bd5ec69871aeb4 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 18 May 2005 18:02:04 +0200 Subject: [ALSA] sound/core/: possible cleanups PCM Midlevel,ALSA Core,Timer Midlevel,ALSA sequencer,Virtual Midi This patch contains the following possible cleanups: - make needlessly global code static - #if 0 the following unused global functions - remove the following unneeded EXPORT_SYMBOL's Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 50a6ee1..d935417 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -848,23 +848,6 @@ int snd_interval_ratnum(snd_interval_t *i, void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params); void _snd_pcm_hw_param_setempty(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var); -int snd_pcm_hw_param_min(snd_pcm_substream_t *substream, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, - unsigned int val, int *dir); -int snd_pcm_hw_param_max(snd_pcm_substream_t *substream, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, - unsigned int val, int *dir); -int snd_pcm_hw_param_setinteger(snd_pcm_substream_t *substream, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var); -int snd_pcm_hw_param_first(snd_pcm_substream_t *substream, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, int *dir); -int snd_pcm_hw_param_last(snd_pcm_substream_t *substream, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, int *dir); int snd_pcm_hw_param_near(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, @@ -876,7 +859,6 @@ int snd_pcm_hw_param_set(snd_pcm_substream_t *pcm, int snd_pcm_hw_params_choose(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); int snd_pcm_hw_refine(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); -int snd_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); int snd_pcm_hw_constraints_init(snd_pcm_substream_t *substream); int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream); diff --git a/include/sound/seq_midi_event.h b/include/sound/seq_midi_event.h index 4357cac..8857e2b 100644 --- a/include/sound/seq_midi_event.h +++ b/include/sound/seq_midi_event.h @@ -41,9 +41,7 @@ struct snd_midi_event_t { }; int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev); -int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize); void snd_midi_event_free(snd_midi_event_t *dev); -void snd_midi_event_init(snd_midi_event_t *dev); void snd_midi_event_reset_encode(snd_midi_event_t *dev); void snd_midi_event_reset_decode(snd_midi_event_t *dev); void snd_midi_event_no_status(snd_midi_event_t *dev, int on); diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h index cf4e238..1ad27e8 100644 --- a/include/sound/seq_virmidi.h +++ b/include/sound/seq_virmidi.h @@ -79,6 +79,5 @@ struct _snd_virmidi_dev { #define SNDRV_VIRMIDI_SEQ_DISPATCH 2 int snd_virmidi_new(snd_card_t *card, int device, snd_rawmidi_t **rrmidi); -int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev); #endif /* __SOUND_SEQ_VIRMIDI */ diff --git a/include/sound/timer.h b/include/sound/timer.h index 57fde99..1898511 100644 --- a/include/sound/timer.h +++ b/include/sound/timer.h @@ -152,6 +152,4 @@ extern int snd_timer_pause(snd_timer_instance_t * timeri); extern void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left); -extern unsigned int snd_timer_system_resolution(void); - #endif /* __SOUND_TIMER_H */ diff --git a/sound/core/pcm.c b/sound/core/pcm.c index d57f4ec..9f4c920 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1049,7 +1049,6 @@ EXPORT_SYMBOL(snd_pcm_release_substream); EXPORT_SYMBOL(snd_pcm_format_name); /* pcm_native.c */ EXPORT_SYMBOL(snd_pcm_link_rwlock); -EXPORT_SYMBOL(snd_pcm_start); #ifdef CONFIG_PM EXPORT_SYMBOL(snd_pcm_suspend); EXPORT_SYMBOL(snd_pcm_suspend_all); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 151fd99..7ce8b21 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1143,7 +1143,8 @@ int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime, #define INT_MIN ((int)((unsigned int)INT_MAX+1)) #endif -void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) +static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) { if (hw_is_mask(var)) { snd_mask_any(hw_param_mask(params, var)); @@ -1163,12 +1164,14 @@ void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) /** * snd_pcm_hw_param_any */ +#if 0 int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) { _snd_pcm_hw_param_any(params, var); return snd_pcm_hw_refine(pcm, params); } +#endif /* 0 */ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) { @@ -1186,11 +1189,13 @@ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) * * Fill PARAMS with full configuration space boundaries */ +#if 0 int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { _snd_pcm_hw_params_any(params); return snd_pcm_hw_refine(pcm, params); } +#endif /* 0 */ /** * snd_pcm_hw_param_value @@ -1198,8 +1203,8 @@ int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) * Return the value for field PAR if it's fixed in configuration space * defined by PARAMS. Return -EINVAL otherwise */ -int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, int *dir) +static int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, int *dir) { if (hw_is_mask(var)) { const snd_mask_t *mask = hw_param_mask_c(params, var); @@ -1303,6 +1308,7 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params, * non integer values. Reduce configuration space accordingly. * Return -EINVAL if the configuration space is empty */ +#if 0 int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) @@ -1317,9 +1323,10 @@ int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm, } return 0; } +#endif /* 0 */ -int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var) +static int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) { int changed; if (hw_is_mask(var)) @@ -1345,9 +1352,9 @@ int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, * values > minimum. Reduce configuration space accordingly. * Return the minimum. */ -int snd_pcm_hw_param_first(snd_pcm_t *pcm, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, int *dir) +static int snd_pcm_hw_param_first(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, int *dir) { int changed = _snd_pcm_hw_param_first(params, var); if (changed < 0) @@ -1359,8 +1366,8 @@ int snd_pcm_hw_param_first(snd_pcm_t *pcm, return snd_pcm_hw_param_value(params, var, dir); } -int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var) +static int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) { int changed; if (hw_is_mask(var)) @@ -1386,9 +1393,9 @@ int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, * values < maximum. Reduce configuration space accordingly. * Return the maximum. */ -int snd_pcm_hw_param_last(snd_pcm_t *pcm, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, int *dir) +static int snd_pcm_hw_param_last(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, int *dir) { int changed = _snd_pcm_hw_param_last(params, var); if (changed < 0) @@ -1437,8 +1444,9 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params, * values < VAL. Reduce configuration space accordingly. * Return new minimum or -EINVAL if the configuration space is empty */ -int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, unsigned int val, int *dir) +static int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, + int *dir) { int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0); if (changed < 0) @@ -1451,8 +1459,9 @@ int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, return snd_pcm_hw_param_value_min(params, var, dir); } -int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, unsigned int val, int dir) +static int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, + int dir) { int changed; int open = 0; @@ -1490,8 +1499,9 @@ int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, * values >= VAL + 1. Reduce configuration space accordingly. * Return new maximum or -EINVAL if the configuration space is empty */ -int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, unsigned int val, int *dir) +static int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, + int *dir) { int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0); if (changed < 0) @@ -2564,9 +2574,6 @@ snd_pcm_sframes_t snd_pcm_lib_readv(snd_pcm_substream_t *substream, EXPORT_SYMBOL(snd_interval_refine); EXPORT_SYMBOL(snd_interval_list); EXPORT_SYMBOL(snd_interval_ratnum); -EXPORT_SYMBOL(snd_interval_muldivk); -EXPORT_SYMBOL(snd_interval_mulkdiv); -EXPORT_SYMBOL(snd_interval_div); EXPORT_SYMBOL(_snd_pcm_hw_params_any); EXPORT_SYMBOL(_snd_pcm_hw_param_min); EXPORT_SYMBOL(_snd_pcm_hw_param_set); @@ -2580,7 +2587,6 @@ EXPORT_SYMBOL(snd_pcm_hw_param_last); EXPORT_SYMBOL(snd_pcm_hw_param_near); EXPORT_SYMBOL(snd_pcm_hw_param_set); EXPORT_SYMBOL(snd_pcm_hw_refine); -EXPORT_SYMBOL(snd_pcm_hw_params); EXPORT_SYMBOL(snd_pcm_hw_constraints_init); EXPORT_SYMBOL(snd_pcm_hw_constraints_complete); EXPORT_SYMBOL(snd_pcm_hw_constraint_list); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index cad9bbd..4e58241 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -337,8 +337,8 @@ out: return err; } -int snd_pcm_hw_params(snd_pcm_substream_t *substream, - snd_pcm_hw_params_t *params) +static int snd_pcm_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *params) { snd_pcm_runtime_t *runtime; int err; diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 21e5690..df1e2bb 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -171,11 +171,13 @@ void snd_midi_event_reset_decode(snd_midi_event_t *dev) spin_unlock_irqrestore(&dev->lock, flags); } +#if 0 void snd_midi_event_init(snd_midi_event_t *dev) { snd_midi_event_reset_encode(dev); snd_midi_event_reset_decode(dev); } +#endif /* 0 */ void snd_midi_event_no_status(snd_midi_event_t *dev, int on) { @@ -185,6 +187,7 @@ void snd_midi_event_no_status(snd_midi_event_t *dev, int on) /* * resize buffer */ +#if 0 int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize) { unsigned char *new_buf, *old_buf; @@ -204,6 +207,7 @@ int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize) kfree(old_buf); return 0; } +#endif /* 0 */ /* * read bytes and encode to sequencer event if finished @@ -517,8 +521,6 @@ static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int coun EXPORT_SYMBOL(snd_midi_event_new); EXPORT_SYMBOL(snd_midi_event_free); -EXPORT_SYMBOL(snd_midi_event_resize_buffer); -EXPORT_SYMBOL(snd_midi_event_init); EXPORT_SYMBOL(snd_midi_event_reset_encode); EXPORT_SYMBOL(snd_midi_event_reset_decode); EXPORT_SYMBOL(snd_midi_event_no_status); diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 3afc7cc0..98de2e7 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -672,7 +672,8 @@ static void queue_broadcast_event(queue_t *q, snd_seq_event_t *ev, int atomic, i * process a received queue-control event. * this function is exported for seq_sync.c. */ -void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop) +static void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, + int atomic, int hop) { switch (ev->type) { case SNDRV_SEQ_EVENT_START: diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h index b1bf551..ea3c542 100644 --- a/sound/core/seq/seq_queue.h +++ b/sound/core/seq/seq_queue.h @@ -111,7 +111,6 @@ int snd_seq_queue_use(int queueid, int client, int use); int snd_seq_queue_is_used(int queueid, int client); int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop); -void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop); /* * 64bit division - for sync stuff.. diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 753f1c0..a7f76fc 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -36,7 +36,8 @@ extern int seq_default_timer_resolution; #define SKEW_BASE 0x10000 /* 16bit shift */ -void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, int tempo, int ppq, int nticks) +static void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, + int tempo, int ppq, int nticks) { if (tempo < 1000000) tick->resolution = (tempo * 1000) / ppq; diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index 4c0872d..287ed68 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h @@ -64,8 +64,6 @@ extern seq_timer_t *snd_seq_timer_new(void); /* delete timer (destructor) */ extern void snd_seq_timer_delete(seq_timer_t **tmr); -void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, int tempo, int ppq, int nticks); - /* */ static inline void snd_seq_timer_update_tick(seq_timer_tick_t *tick, unsigned long resolution) { diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 58c56a1..a66484b5 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -110,7 +110,7 @@ static int snd_virmidi_dev_receive_event(snd_virmidi_dev_t *rdev, snd_seq_event_ * handler of a remote port which is attached to the virmidi via * SNDRV_VIRMIDI_SEQ_ATTACH. */ -/* exported */ +#if 0 int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev) { snd_virmidi_dev_t *rdev; @@ -118,6 +118,7 @@ int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev) rdev = rmidi->private_data; return snd_virmidi_dev_receive_event(rdev, ev); } +#endif /* 0 */ /* * event handler of virmidi port @@ -548,4 +549,3 @@ module_init(alsa_virmidi_init) module_exit(alsa_virmidi_exit) EXPORT_SYMBOL(snd_virmidi_new); -EXPORT_SYMBOL(snd_virmidi_receive); diff --git a/sound/core/sound.c b/sound/core/sound.c index 88e0520..fa92e66 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -431,7 +431,6 @@ EXPORT_SYMBOL(snd_card_pci_resume); EXPORT_SYMBOL(snd_device_new); EXPORT_SYMBOL(snd_device_register); EXPORT_SYMBOL(snd_device_free); -EXPORT_SYMBOL(snd_device_free_all); /* isadma.c */ #ifdef CONFIG_ISA EXPORT_SYMBOL(snd_dma_program); diff --git a/sound/core/timer.c b/sound/core/timer.c index cb011a1..d67a5e9 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -845,7 +845,7 @@ int snd_timer_dev_register(snd_device_t *dev) return 0; } -int snd_timer_unregister(snd_timer_t *timer) +static int snd_timer_unregister(snd_timer_t *timer) { struct list_head *p, *n; snd_timer_instance_t *ti; @@ -946,11 +946,6 @@ struct snd_timer_system_private { unsigned long correction; }; -unsigned int snd_timer_system_resolution(void) -{ - return 1000000000L / HZ; -} - static void snd_timer_s_function(unsigned long data) { snd_timer_t *timer = (snd_timer_t *)data; @@ -1938,4 +1933,3 @@ EXPORT_SYMBOL(snd_timer_global_free); EXPORT_SYMBOL(snd_timer_global_register); EXPORT_SYMBOL(snd_timer_global_unregister); EXPORT_SYMBOL(snd_timer_interrupt); -EXPORT_SYMBOL(snd_timer_system_resolution); -- cgit v0.10.2 From 58c1f8acdeec4989e5dce1a3aec16926342d7f4b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 May 2005 16:13:00 +0200 Subject: [ALSA] Fix resume of via82xx-modem VIA82xx-modem driver Fix the resume of via82xx-modem, removing invalid __devinit. Signed-off-by: Takashi Iwai diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 098870a..276ce52 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -938,7 +938,7 @@ static void __devinit snd_via82xx_proc_init(via82xx_t *chip) * */ -static int __devinit snd_via82xx_chip_init(via82xx_t *chip) +static int snd_via82xx_chip_init(via82xx_t *chip) { unsigned int val; int max_count; -- cgit v0.10.2 From 82f008c2b651eefbf293546440fd226580b0c111 Mon Sep 17 00:00:00 2001 From: Ville Syrjala Date: Fri, 20 May 2005 18:40:38 +0200 Subject: [ALSA] maestro3: Add hardware volume control quirk list Maestro3 driver Add a hardware volume quirk list to the maestro3 driver. Details were taken from the Windows driver. Hardware volume control is enabled only for the systems in the list. Signed-off-by: Ville Syrjala Signed-off-by: Takashi Iwai diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 3690ea0..096f151 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -779,6 +779,12 @@ struct m3_quirk { (e.g. for IrDA on Dell Inspirons) */ }; +struct m3_hv_quirk { + u16 vendor, device, subsystem_vendor, subsystem_device; + u32 config; /* ALLEGRO_CONFIG hardware volume bits */ + int is_omnibook; /* Do HP OmniBook GPIO magic? */ +}; + struct m3_list { int curlen; int mem_addr; @@ -828,6 +834,7 @@ struct snd_m3 { struct pci_dev *pci; struct m3_quirk *quirk; + struct m3_hv_quirk *hv_quirk; int dacs_active; int timer_users; @@ -856,7 +863,7 @@ struct snd_m3 { snd_kcontrol_t *master_switch; snd_kcontrol_t *master_volume; struct tasklet_struct hwvol_tq; - + #ifdef CONFIG_PM u16 *suspend_mem; #endif @@ -973,6 +980,71 @@ static struct m3_quirk m3_quirk_list[] = { { NULL } }; +/* These values came from the Windows driver. */ +static struct m3_hv_quirk m3_hv_quirk_list[] = { + /* Allegro chips */ + { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */ + { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 }, + /* Maestro3 chips */ + { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */ + { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */ + { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, + { 0 } +}; /* * lowlevel functions @@ -2392,21 +2464,27 @@ snd_m3_chip_init(m3_t *chip) DISABLE_LEGACY); pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); - /* - * Volume buttons on some HP OmniBook laptops (500 and 6000 at least) - * don't work correctly. This makes them work for the most part. - * Volume up and down buttons on the laptop side work perfectly. - * Fn+cursor_up (volme up) works, Fn+cursor_down (volume down) doesn't, - * Fn+F8 (mute) works acts as volume up. - */ - outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK); - outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION); - outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA); - outw(0xffff, io + GPIO_MASK); - + if (chip->hv_quirk && chip->hv_quirk->is_omnibook) { + /* + * Volume buttons on some HP OmniBook laptops don't work + * correctly. This makes them work for the most part. + * + * Volume up and down buttons on the laptop side work. + * Fn+cursor_up (volme up) works. + * Fn+cursor_down (volume down) doesn't work. + * Fn+F7 (mute) works acts as volume up. + */ + outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK); + outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION); + outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA); + outw(0xffff, io + GPIO_MASK); + } pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); - n &= ~HV_BUTTON_FROM_GD; - n |= HV_CTRL_ENABLE | REDUCED_DEBOUNCE; + n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); + if (chip->hv_quirk) + n |= chip->hv_quirk->config; + /* For some reason we must always use reduced debounce. */ + n |= REDUCED_DEBOUNCE; n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); @@ -2594,7 +2672,7 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, m3_t *chip; int i, err; struct m3_quirk *quirk; - u16 subsystem_vendor, subsystem_device; + struct m3_hv_quirk *hv_quirk; static snd_device_ops_t ops = { .dev_free = snd_m3_dev_free, }; @@ -2632,18 +2710,25 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, chip->pci = pci; chip->irq = -1; - pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); - pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); - for (quirk = m3_quirk_list; quirk->vendor; quirk++) { - if (subsystem_vendor == quirk->vendor && - subsystem_device == quirk->device) { + if (pci->subsystem_vendor == quirk->vendor && + pci->subsystem_device == quirk->device) { printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name); chip->quirk = quirk; break; } } + for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) { + if (pci->vendor == hv_quirk->vendor && + pci->device == hv_quirk->device && + pci->subsystem_vendor == hv_quirk->subsystem_vendor && + pci->subsystem_device == hv_quirk->subsystem_device) { + chip->hv_quirk = hv_quirk; + break; + } + } + chip->external_amp = enable_amp; if (amp_gpio >= 0 && amp_gpio <= 0x0f) chip->amp_gpio = amp_gpio; -- cgit v0.10.2 From 1f82941e82422fcb15d63431e163bf4f0b9389d9 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 21 May 2005 16:23:37 +0200 Subject: [ALSA] Implement surround71 outputs on SB Live 24bit. CA0106 driver Notes: Requires updated alsa-lib. Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 231ecac..48e2486 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -113,7 +113,7 @@ static int snd_ca0106_shared_spdif_put(snd_kcontrol_t * kcontrol, } else { /* Analog */ snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000b0000); + snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); mask = inl(emu->port + GPIO) | 0x101; @@ -437,7 +437,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_analog_center_lfe = static snd_kcontrol_new_t snd_ca0106_volume_control_analog_unknown = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Unknown Volume", + .name = "Analog Side Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_analog_unknown, .put = snd_ca0106_volume_put_analog_unknown -- cgit v0.10.2 From 8f55fbb0fdb821023ff0a816ebf5056188891ff0 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 21 May 2005 16:45:58 +0200 Subject: [ALSA] When the alsamixer says 'SPDIF Out [Off]', SPDIF output should be off and Analog output should be on. CA0106 driver This fixes a bug whereby when the snd-ca0106 module first loads, alsamixer says 'SPDIF Out [Off]' but no analog sound comes from the speakers. This covers any bug reports that said things like 'mixer fails to remember analog output on, when the system is rebooted.' Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index d4cb8ed..90d493c 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1114,7 +1114,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ /* Analog or Digital output */ snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000b0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers */ + snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ chip->spdif_enable = 0; /* Set digital SPDIF output off */ chip->capture_source = 3; /* Set CAPTURE_SOURCE */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ @@ -1145,7 +1145,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ - outl(0x005f4300, chip->port+GPIO); /* Analog */ + outl(0x005f4301, chip->port+GPIO); /* Analog */ } else { outl(0x0, chip->port+GPIO); outl(0x005f03a3, chip->port+GPIO); /* Analog */ -- cgit v0.10.2 From 1baa705b75124df7cfe3d5d2706f794a14d26ad0 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 21 May 2005 22:35:58 +0200 Subject: [ALSA] Tidy up card recognition. CA0106 driver Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index deb0288..c623858 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -508,9 +508,17 @@ struct snd_ca0106_pcm { unsigned short running; }; +typedef struct { + u32 serial; + char * name; + int ac97; + int gpio_type; +} ca0106_details_t; + // definition of the chip-specific record struct snd_ca0106 { snd_card_t *card; + ca0106_details_t *details; struct pci_dev *pci; unsigned long port; diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 90d493c..a56e68e 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -161,18 +161,29 @@ MODULE_PARM_DESC(enable, "Enable the CA0106 soundcard."); #include "ca0106.h" -typedef struct { - u32 serial; - char * name; -} ca0106_names_t; - -static ca0106_names_t ca0106_chip_names[] = { - { 0x10021102, "AudigyLS [SB0310]"} , - { 0x10051102, "AudigyLS [SB0310b]"} , /* Unknown AudigyLS that also says SB0310 on it */ - { 0x10061102, "Live! 7.1 24bit [SB0410]"} , /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ - { 0x10071102, "Live! 7.1 24bit [SB0413]"} , /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ - { 0x10091462, "MSI K8N Diamond MB [SB0438]"}, /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ - { 0, "AudigyLS [Unknown]" } +static ca0106_details_t ca0106_chip_details[] = { + /* AudigyLS[SB0310] */ + { .serial = 0x10021102, + .name = "AudigyLS [SB0310]", + .ac97 = 1 } , + /* Unknown AudigyLS that also says SB0310 on it */ + { .serial = 0x10051102, + .name = "AudigyLS [SB0310b]", + .ac97 = 1 } , + /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ + { .serial = 0x10061102, + .name = "Live! 7.1 24bit [SB0410]", + .gpio_type = 1 } , + /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ + { .serial = 0x10071102, + .name = "Live! 7.1 24bit [SB0413]", + .gpio_type = 1 } , + /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ + { .serial = 0x10091462, + .name = "MSI K8N Diamond MB [SB0438]", + .gpio_type = 1 } , + { .serial = 0, + .name = "AudigyLS [Unknown]" } }; /* hardware definition */ @@ -994,6 +1005,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, ca0106_t **rchip) { ca0106_t *chip; + ca0106_details_t *c; int err; int ch; static snd_device_ops_t ops = { @@ -1055,6 +1067,15 @@ static int __devinit snd_ca0106_create(snd_card_t *card, printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model, chip->revision, chip->serial); #endif + strcpy(card->driver, "CA0106"); + strcpy(card->shortname, "CA0106"); + + for (c=ca0106_chip_details; c->serial; c++) { + if (c->serial == chip->serial) break; + } + chip->details = c; + sprintf(card->longname, "%s at 0x%lx irq %i", + c->name, chip->port, chip->irq); outl(0, chip->port + INTE); @@ -1139,9 +1160,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ chip->capture_source = 3; /* Set CAPTURE_SOURCE */ - if ((chip->serial == 0x10061102) || - (chip->serial == 0x10071102) || - (chip->serial == 0x10091462)) { /* The SB0410 and SB0413 use GPIO differently. */ + if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ @@ -1173,7 +1192,6 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, static int dev; snd_card_t *card; ca0106_t *chip; - ca0106_names_t *c; int err; if (dev >= SNDRV_CARDS) @@ -1208,9 +1226,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_card_free(card); return err; } - if ((chip->serial != 0x10061102) && - (chip->serial != 0x10071102) && - (chip->serial != 0x10091462) ) { /* The SB0410 and SB0413 do not have an ac97 chip. */ + if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ if ((err = snd_ca0106_ac97(chip)) < 0) { snd_card_free(card); return err; @@ -1223,15 +1239,6 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_ca0106_proc_init(chip); - strcpy(card->driver, "CA0106"); - strcpy(card->shortname, "CA0106"); - - for (c=ca0106_chip_names; c->serial; c++) { - if (c->serial == chip->serial) break; - } - sprintf(card->longname, "%s at 0x%lx irq %i", - c->name, chip->port, chip->irq); - if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; -- cgit v0.10.2 From 209ac85d76e4edf05779b4bd5c2a92b059e9ab4d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 23 May 2005 10:29:53 +0200 Subject: [ALSA] sound/isa/: cleanups GUS Library This patch contains the following possible cleanups: - make needlesly global code static - #if 0 the following unused global functions: - gus/gus_volume.c: snd_gf1_gvol_to_lvol_raw - gus/gus_volume.c: snd_gf1_calc_ramp_rate - gus/gus_volume.c: snd_gf1_compute_vibrato - gus/gus_volume.c: snd_gf1_compute_pitchbend - gus/gus_volume.c: snd_gf1_compute_freq - gus/gus_io.c: snd_gf1_i_adlib_write - gus/gus_io.c: snd_gf1_i_write_addr - gus/gus_io.c: snd_gf1_pokew - gus/gus_io.c: snd_gf1_peekw - gus/gus_io.c: snd_gf1_dram_setmem - gus/gus_io.c: snd_gf1_print_global_registers - gus/gus_io.c: snd_gf1_print_setup_registers - gus/gus_io.c: snd_gf1_peek_print_block - gus/gus_io.c: snd_gf1_print_setup_registers - gus/gus_io.c: snd_gf1_peek_print_block - #if 0 the following unused global variable: - gus/gus_tables.h: snd_gf1_scale_table - remove the following unneeded EXPORT_SYMBOL's: - gus/gus_main.c: snd_gf1_i_write16 - gus/gus_main.c: snd_gf1_start - gus/gus_main.c: snd_gf1_stop Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai diff --git a/include/sound/gus.h b/include/sound/gus.h index 8b6287a..b4b461c 100644 --- a/include/sound/gus.h +++ b/include/sound/gus.h @@ -526,9 +526,6 @@ extern void snd_gf1_adlib_write(snd_gus_card_t * gus, unsigned char reg, unsigne extern void snd_gf1_dram_addr(snd_gus_card_t * gus, unsigned int addr); extern void snd_gf1_poke(snd_gus_card_t * gus, unsigned int addr, unsigned char data); extern unsigned char snd_gf1_peek(snd_gus_card_t * gus, unsigned int addr); -extern void snd_gf1_pokew(snd_gus_card_t * gus, unsigned int addr, unsigned short data); -extern unsigned short snd_gf1_peekw(snd_gus_card_t * gus, unsigned int addr); -extern void snd_gf1_dram_setmem(snd_gus_card_t * gus, unsigned int addr, unsigned short value, unsigned int count); extern void snd_gf1_write_addr(snd_gus_card_t * gus, unsigned char reg, unsigned int addr, short w_16bit); extern unsigned int snd_gf1_read_addr(snd_gus_card_t * gus, unsigned char reg, short w_16bit); extern void snd_gf1_i_ctrl_stop(snd_gus_card_t * gus, unsigned char reg); @@ -544,9 +541,6 @@ extern inline unsigned short snd_gf1_i_read16(snd_gus_card_t * gus, unsigned cha { return snd_gf1_i_look16(gus, reg | 0x80); } -extern void snd_gf1_i_adlib_write(snd_gus_card_t * gus, unsigned char reg, unsigned char data); -extern void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg, unsigned int addr, short w_16bit); -extern unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus, unsigned char reg, short w_16bit); extern void snd_gf1_select_active_voices(snd_gus_card_t * gus); @@ -580,10 +574,6 @@ extern void snd_gf1_lfo_command(snd_gus_card_t * gus, int voice, unsigned char * void snd_gf1_mem_lock(snd_gf1_mem_t * alloc, int xup); int snd_gf1_mem_xfree(snd_gf1_mem_t * alloc, snd_gf1_mem_block_t * block); -snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, - unsigned int address); -snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc, - unsigned int *share_id); snd_gf1_mem_block_t *snd_gf1_mem_alloc(snd_gf1_mem_t * alloc, int owner, char *name, int size, int w_16, int align, unsigned int *share_id); @@ -608,23 +598,13 @@ int snd_gf1_dma_transfer_block(snd_gus_card_t * gus, /* gus_volume.c */ unsigned short snd_gf1_lvol_to_gvol_raw(unsigned int vol); -unsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol); -unsigned int snd_gf1_calc_ramp_rate(snd_gus_card_t * gus, - unsigned short start, - unsigned short end, - unsigned int us); unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq2); -unsigned short snd_gf1_compute_pitchbend(unsigned short pitchbend, unsigned short sens); -unsigned short snd_gf1_compute_freq(unsigned int freq, - unsigned int rate, - unsigned short mix_rate); /* gus_reset.c */ void snd_gf1_set_default_handlers(snd_gus_card_t * gus, unsigned int what); void snd_gf1_smart_stop_voice(snd_gus_card_t * gus, unsigned short voice); void snd_gf1_stop_voice(snd_gus_card_t * gus, unsigned short voice); -void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max); void snd_gf1_stop_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max); snd_gus_voice_t *snd_gf1_alloc_voice(snd_gus_card_t * gus, int type, int client, int port); void snd_gf1_free_voice(snd_gus_card_t * gus, snd_gus_voice_t *voice); @@ -641,9 +621,6 @@ int snd_gf1_pcm_new(snd_gus_card_t * gus, int pcm_dev, int control_index, snd_pc #ifdef CONFIG_SND_DEBUG extern void snd_gf1_print_voice_registers(snd_gus_card_t * gus); -extern void snd_gf1_print_global_registers(snd_gus_card_t * gus); -extern void snd_gf1_print_setup_registers(snd_gus_card_t * gus); -extern void snd_gf1_peek_print_block(snd_gus_card_t * gus, unsigned int addr, int count, int w_16bit); #endif /* gus.c */ diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c index f0570f2..337b0e2 100644 --- a/sound/isa/gus/gus_io.c +++ b/sound/isa/gus/gus_io.c @@ -244,6 +244,8 @@ unsigned short snd_gf1_i_look16(snd_gus_card_t * gus, unsigned char reg) return res; } +#if 0 + void snd_gf1_i_adlib_write(snd_gus_card_t * gus, unsigned char reg, unsigned char data) @@ -265,6 +267,8 @@ void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg, spin_unlock_irqrestore(&gus->reg_lock, flags); } +#endif /* 0 */ + unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus, unsigned char reg, short w_16bit) { @@ -329,6 +333,8 @@ unsigned char snd_gf1_peek(snd_gus_card_t * gus, unsigned int addr) return res; } +#if 0 + void snd_gf1_pokew(snd_gus_card_t * gus, unsigned int addr, unsigned short data) { unsigned long flags; @@ -405,9 +411,7 @@ void snd_gf1_dram_setmem(snd_gus_card_t * gus, unsigned int addr, spin_unlock_irqrestore(&gus->reg_lock, flags); } -/* - - */ +#endif /* 0 */ void snd_gf1_select_active_voices(snd_gus_card_t * gus) { @@ -469,6 +473,8 @@ void snd_gf1_print_voice_registers(snd_gus_card_t * gus) printk(" -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c)); } +#if 0 + void snd_gf1_print_global_registers(snd_gus_card_t * gus) { unsigned char global_mode = 0x00; @@ -528,4 +534,6 @@ void snd_gf1_peek_print_block(snd_gus_card_t * gus, unsigned int addr, int count } } +#endif /* 0 */ + #endif diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 73f81c1..94bbd34 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -459,7 +459,6 @@ EXPORT_SYMBOL(snd_gf1_write16); EXPORT_SYMBOL(snd_gf1_look16); EXPORT_SYMBOL(snd_gf1_i_write8); EXPORT_SYMBOL(snd_gf1_i_look8); -EXPORT_SYMBOL(snd_gf1_i_write16); EXPORT_SYMBOL(snd_gf1_i_look16); EXPORT_SYMBOL(snd_gf1_dram_addr); EXPORT_SYMBOL(snd_gf1_write_addr); @@ -470,8 +469,6 @@ EXPORT_SYMBOL(snd_gf1_alloc_voice); EXPORT_SYMBOL(snd_gf1_free_voice); EXPORT_SYMBOL(snd_gf1_ctrl_stop); EXPORT_SYMBOL(snd_gf1_stop_voice); -EXPORT_SYMBOL(snd_gf1_start); -EXPORT_SYMBOL(snd_gf1_stop); /* gus_mixer.c */ EXPORT_SYMBOL(snd_gf1_new_mixer); /* gus_pcm.c */ diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index bfc2b91..609838e 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -39,8 +39,8 @@ void snd_gf1_mem_lock(snd_gf1_mem_t * alloc, int xup) } } -snd_gf1_mem_block_t *snd_gf1_mem_xalloc(snd_gf1_mem_t * alloc, - snd_gf1_mem_block_t * block) +static snd_gf1_mem_block_t *snd_gf1_mem_xalloc(snd_gf1_mem_t * alloc, + snd_gf1_mem_block_t * block) { snd_gf1_mem_block_t *pblock, *nblock; @@ -105,8 +105,8 @@ int snd_gf1_mem_xfree(snd_gf1_mem_t * alloc, snd_gf1_mem_block_t * block) return 0; } -snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, - unsigned int address) +static snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, + unsigned int address) { snd_gf1_mem_block_t *block; @@ -118,8 +118,8 @@ snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, return NULL; } -snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc, - unsigned int *share_id) +static snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc, + unsigned int *share_id) { snd_gf1_mem_block_t *block; diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c index b4e66f6..ef687ab 100644 --- a/sound/isa/gus/gus_reset.c +++ b/sound/isa/gus/gus_reset.c @@ -161,7 +161,8 @@ void snd_gf1_stop_voice(snd_gus_card_t * gus, unsigned short voice) #endif } -void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max) +static void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, + unsigned short v_max) { unsigned long flags; unsigned int daddr; diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c index 66552e6..f51c386 100644 --- a/sound/isa/gus/gus_synth.c +++ b/sound/isa/gus/gus_synth.c @@ -99,7 +99,8 @@ static void snd_gus_synth_free_private_instruments(snd_gus_port_t *p, int client snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0); } -int snd_gus_synth_event_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop) +static int snd_gus_synth_event_input(snd_seq_event_t *ev, int direct, + void *private_data, int atomic, int hop) { snd_gus_port_t * p = (snd_gus_port_t *) private_data; diff --git a/sound/isa/gus/gus_tables.h b/sound/isa/gus/gus_tables.h index ed8e9d8..4adf098 100644 --- a/sound/isa/gus/gus_tables.h +++ b/sound/isa/gus/gus_tables.h @@ -23,6 +23,8 @@ #ifdef __GUS_TABLES_ALLOC__ +#if 0 + unsigned int snd_gf1_scale_table[SNDRV_GF1_SCALE_TABLE_SIZE] = { 8372, 8870, 9397, 9956, 10548, 11175, @@ -49,6 +51,8 @@ unsigned int snd_gf1_scale_table[SNDRV_GF1_SCALE_TABLE_SIZE] = 12123977, 12844906 }; +#endif /* 0 */ + unsigned short snd_gf1_atten_table[SNDRV_GF1_ATTEN_TABLE_SIZE] = { 4095 /* 0 */,1789 /* 1 */,1533 /* 2 */,1383 /* 3 */,1277 /* 4 */, 1195 /* 5 */,1127 /* 6 */,1070 /* 7 */,1021 /* 8 */,978 /* 9 */, diff --git a/sound/isa/gus/gus_volume.c b/sound/isa/gus/gus_volume.c index b72bcfb..3d36f6c 100644 --- a/sound/isa/gus/gus_volume.c +++ b/sound/isa/gus/gus_volume.c @@ -55,6 +55,8 @@ unsigned short snd_gf1_lvol_to_gvol_raw(unsigned int vol) return (e << 8) | m; } +#if 0 + unsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol) { unsigned int rvol; @@ -108,6 +110,8 @@ unsigned int snd_gf1_calc_ramp_rate(snd_gus_card_t * gus, return (range << 6) | (increment & 0x3f); } +#endif /* 0 */ + unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq16) { freq16 >>= 3; @@ -120,6 +124,8 @@ unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq16) return ((freq16 << 9) + (gus->gf1.playback_freq >> 1)) / gus->gf1.playback_freq; } +#if 0 + short snd_gf1_compute_vibrato(short cents, unsigned short fc_register) { static short vibrato_table[] = @@ -208,3 +214,5 @@ unsigned short snd_gf1_compute_freq(unsigned int freq, } return (unsigned short) fc; } + +#endif /* 0 */ -- cgit v0.10.2 From e6e514fa825be7362a955ba43d6fd18896d375c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 May 2005 10:33:08 +0200 Subject: [ALSA] Add the vendor 0x1558 to PM whitelist of es1968 ES1968 driver Added the vendor id 0x1558 to the power management whitelist of es1968 driver. Signed-off-by: Takashi Iwai diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index da10d40..ea889b3 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2559,6 +2559,7 @@ static struct ess_device_list pm_whitelist[] __devinitdata = { { TYPE_MAESTRO2E, 0x103c }, { TYPE_MAESTRO2E, 0x1179 }, { TYPE_MAESTRO2E, 0x14c0 }, /* HP omnibook 4150 */ + { TYPE_MAESTRO2E, 0x1558 }, }; static struct ess_device_list mpu_blacklist[] __devinitdata = { -- cgit v0.10.2 From d6e33796b5857adf418b07f8f7ce65f46163b2f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 10:40:49 +0200 Subject: [ALSA] cmipci: Fix obsolete description Documentation Fixed obsolete description about CMIPCI driver. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/CMIPCI.txt b/Documentation/sound/alsa/CMIPCI.txt index 4a7df77..1872e24 100644 --- a/Documentation/sound/alsa/CMIPCI.txt +++ b/Documentation/sound/alsa/CMIPCI.txt @@ -89,19 +89,22 @@ and use the interleaved 4 channel data. There are some control switchs affecting to the speaker connections: -"Line-In As Rear" - As mentioned above, the line-in jack is used - for the rear (3th and 4th channels) output. -"Line-In As Bass" - The line-in jack is used for the bass (5th - and 6th channels) output. -"Mic As Center/LFE" - The mic jack is used for the bass output. - If this switch is on, you cannot use a microphone as a capture - source, of course. - +"Line-In Mode" - an enum control to change the behavior of line-in + jack. Either "Line-In", "Rear Output" or "Bass Output" can + be selected. The last item is available only with model 039 + or newer. + When "Rear Output" is chosen, the surround channels 3 and 4 + are output to line-in jack. +"Mic-In Mode" - an enum control to change the behavior of mic-in + jack. Either "Mic-In" or "Center/LFE Output" can be + selected. + When "Center/LFE Output" is chosen, the center and bass + channels (channels 5 and 6) are output to mic-in jack. Digital I/O ----------- -The CM8x38 provides the excellent SPDIF capability with very chip +The CM8x38 provides the excellent SPDIF capability with very cheap price (yes, that's the reason I bought the card :) The SPDIF playback and capture are done via the third PCM device @@ -122,8 +125,9 @@ respectively, so you cannot playback both analog and digital streams simultaneously. To enable SPDIF output, you need to turn on "IEC958 Output Switch" -control via mixer or alsactl. Then you'll see the red light on from -the card so you know that's working obviously :) +control via mixer or alsactl ("IEC958" is the official name of +so-called S/PDIF). Then you'll see the red light on from the card so +you know that's working obviously :) The SPDIF input is always enabled, so you can hear SPDIF input data from line-out with "IEC958 In Monitor" switch at any time (see below). @@ -205,9 +209,10 @@ In addition to the standard SB mixer, CM8x38 provides more functions. MIDI CONTROLLER --------------- -The MPU401-UART interface is enabled as default only for the first -(CMIPCI) card. You need to set module option "midi_port" properly -for the 2nd (CMIPCI) card. +The MPU401-UART interface is disabled as default. You need to set +module option "mpu_port" with a valid I/O port address to enable the +MIDI support. The valid I/O ports are 0x300, 0x310, 0x320 and 0x330. +Choose the value which doesn't conflict with other cards. There is _no_ hardware wavetable function on this chip (except for OPL3 synth below). @@ -229,9 +234,11 @@ I don't know why.. Joystick and Modem ------------------ -The joystick and modem should be available by enabling the control -switch "Joystick" and "Modem" respectively. But I myself have never -tested them yet. +The legacy joystick is supported. To enable the joystick support, pass +joystick_port=1 module option. The value 1 means the auto-detection. +If the auto-detection fails, try to pass the exact I/O address. + +The modem is enabled dynamically via a card control switch "Modem". Debugging Information -- cgit v0.10.2 From b9cce37411edd668ae5dbc16aa9653800c8e0744 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 13:16:56 +0200 Subject: [ALSA] Add Shuttle SN25P support ICE1712 driver Added the support for Shuttle SN25P. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 3bd9262..ab61e38 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c @@ -110,6 +110,15 @@ struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { .eeprom_size = sizeof(k8x800_eeprom), .eeprom_data = k8x800_eeprom, }, + { + .subvendor = VT1720_SUBDEVICE_SN25P, + .name = "Shuttle SN25P", + /* identical with k8x800 */ + .chip_init = k8x800_init, + .build_controls = k8x800_add_controls, + .eeprom_size = sizeof(k8x800_eeprom), + .eeprom_data = k8x800_eeprom, + }, { } /* terminator */ }; diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h index f949eb8..e0b613c 100644 --- a/sound/pci/ice1712/vt1720_mobo.h +++ b/sound/pci/ice1712/vt1720_mobo.h @@ -33,6 +33,7 @@ #define VT1720_SUBDEVICE_ZNF3_150 0x0f2741f6 #define VT1720_SUBDEVICE_ZNF3_250 0x0f2745f6 #define VT1720_SUBDEVICE_9CJS 0x0f272327 +#define VT1720_SUBDEVICE_SN25P 0x97123650 extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[]; -- cgit v0.10.2 From c9bce91f902737395c72d037d70effb5fcbc53b4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 13:41:03 +0200 Subject: [ALSA] Update documentation for ice1712 and ice1724 Documentation,ICE1712 driver Updated the documentation for ice1712 and ice1724 drivers. Added the device description for shuttle SN25P missing in the last patch. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 5a7f7f5..bb31ae7 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -688,15 +688,19 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * TerraTec EWS 88D * TerraTec EWX 24/96 * TerraTec DMX 6Fire + * TerraTec Phase 88 * Hoontech SoundTrack DSP 24 * Hoontech SoundTrack DSP 24 Value * Hoontech SoundTrack DSP 24 Media 7.1 + * Event Electronics, EZ8 * Digigram VX442 + * Lionstracs, Mediastaton model - Use the given board model, one of the following: delta1010, dio2496, delta66, delta44, audiophile, delta410, delta1010lt, vx442, ewx2496, ews88mt, ews88mt_new, ews88d, - dmx6fire, dsp24, dsp24_value, dsp24_71, ez8 + dmx6fire, dsp24, dsp24_value, dsp24_71, ez8, + phase88, mediastation omni - Omni I/O support for MidiMan M-Audio Delta44/66 cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever) in msec resolution, default value is 500 (0.5 sec) @@ -705,20 +709,44 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. is not used with all Envy24 based cards (for example in the MidiMan Delta serie). + Note: The supported board is detected by reading EEPROM or PCI + SSID (if EEPROM isn't available). You can override the + model by passing "model" module option in case that the + driver isn't configured properly or you want to try another + type for testing. + Module snd-ice1724 ------------------ - Module for Envy24HT (VT/ICE1724) based PCI sound cards. + Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards. * MidiMan M Audio Revolution 7.1 * AMP Ltd AUDIO2000 - * TerraTec Aureon Sky-5.1, Space-7.1 + * TerraTec Aureon 5.1 Sky + * TerraTec Aureon 7.1 Space + * TerraTec Aureon 7.1 Universe + * TerraTec Phase 22 + * TerraTec Phase 28 + * AudioTrak Prodigy 7.1 + * AudioTrak Prodigy 192 + * Pontis MS300 + * Albatron K8X800 Pro II + * Chaintech ZNF3-150 + * Chaintech ZNF3-250 + * Chaintech 9CJS + * Shuttle SN25P model - Use the given board model, one of the following: - revo71, amp2000, prodigy71, aureon51, aureon71, - k8x800 + revo71, amp2000, prodigy71, prodigy192, aureon51, + aureon71, universe, k8x800, phase22, phase28, ms300 Module supports up to 8 cards and autoprobe. + Note: The supported board is detected by reading EEPROM or PCI + SSID (if EEPROM isn't available). You can override the + model by passing "model" module option in case that the + driver isn't configured properly or you want to try another + type for testing. + Module snd-intel8x0 ------------------- diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h index e0b613c..0b1b0ee 100644 --- a/sound/pci/ice1712/vt1720_mobo.h +++ b/sound/pci/ice1712/vt1720_mobo.h @@ -27,7 +27,8 @@ #define VT1720_MOBO_DEVICE_DESC "{Albatron,K8X800 Pro II},"\ "{Chaintech,ZNF3-150},"\ "{Chaintech,ZNF3-250},"\ - "{Chaintech,9CJS}," + "{Chaintech,9CJS},"\ + "{Shuttle,SN25P}," #define VT1720_SUBDEVICE_K8X800 0xf217052c #define VT1720_SUBDEVICE_ZNF3_150 0x0f2741f6 -- cgit v0.10.2 From 23854c30021fb6da1a76a0e6901b35be03419d5f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 15:22:40 +0200 Subject: [ALSA] Add comments for Sound Core Added (minimal) comments for in Kconfig, so that configurators can choose this entry explicitly. A more descriptive comment by someone else is appreciated... Signed-off-by: Takashi Iwai diff --git a/sound/Kconfig b/sound/Kconfig index 047d59e..fe17515 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -42,6 +42,11 @@ menu "Advanced Linux Sound Architecture" config SND tristate "Advanced Linux Sound Architecture" depends on SOUND + help + Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), + the new base sound system. + + For more information, see http://www.alsa-project.org/ source "sound/core/Kconfig" -- cgit v0.10.2 From 62144100471e940468d7a0f2d989df193afe870c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 17:24:59 +0200 Subject: [ALSA] Make docproc happy PCM Midlevel Make docproc happy by moving '#if 0' before comments. Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 7ce8b21..c5bfd09 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1161,10 +1161,10 @@ static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_BUG(); } +#if 0 /** * snd_pcm_hw_param_any */ -#if 0 int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) { @@ -1184,12 +1184,12 @@ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) params->info = ~0U; } +#if 0 /** * snd_pcm_hw_params_any * * Fill PARAMS with full configuration space boundaries */ -#if 0 int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { _snd_pcm_hw_params_any(params); @@ -1301,6 +1301,7 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params, return changed; } +#if 0 /** * snd_pcm_hw_param_setinteger * @@ -1308,7 +1309,6 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params, * non integer values. Reduce configuration space accordingly. * Return -EINVAL if the configuration space is empty */ -#if 0 int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) -- cgit v0.10.2 From 9baf6507ff4d0dcab22460e8785582d4eaadebeb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 17:27:00 +0200 Subject: [ALSA] Use standard form for URL Sound Core Use the standard form with <> for URL in Kconfig help texts. Signed-off-by: Takashi Iwai diff --git a/sound/Kconfig b/sound/Kconfig index fe17515..ee794ae 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -46,7 +46,7 @@ config SND Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), the new base sound system. - For more information, see http://www.alsa-project.org/ + For more information, see source "sound/core/Kconfig" -- cgit v0.10.2 From 033a1f10923bdc3646750eef471a618f9d4c074b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 May 2005 16:41:43 +0200 Subject: [ALSA] hda-code: Fix the array size of codec list HDA Codec driver Fixed the wrong array size of the codec pointer list. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 43fc245..1b12035 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -419,7 +419,7 @@ struct hda_bus { /* codec linked list */ struct list_head codec_list; - struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS]; /* caddr -> codec */ + struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */ struct semaphore cmd_mutex; -- cgit v0.10.2 From 71fe7b82db923e0f71b05deeb54fce75d5a4d08d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 May 2005 18:11:40 +0200 Subject: [ALSA] Fix ALC880 capture problems HDA Codec driver Fixed the capture on some ALC880 devices. The node 0x07 is sometimes invalid as an ADC. Also, the intialization of ADC nodes are fixed on some models. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9f12d1f..ee1c4cd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -97,10 +97,20 @@ static hda_nid_t alc880_z71v_dac_nids[1] = { 0x02 }; +#if 0 +/* The datasheet says the node 0x07 is connected from inputs, + * but it shows zero connection in the real implementation. + */ static hda_nid_t alc880_adc_nids[3] = { /* ADC0-2 */ 0x07, 0x08, 0x09, }; +#else +static hda_nid_t alc880_adc_nids[2] = { + /* ADC1-2 */ + 0x08, 0x09, +}; +#endif #define ALC880_DIGOUT_NID 0x06 #define ALC880_DIGIN_NID 0x0a @@ -380,10 +390,11 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + /* We don't use NID 0x07 - see above */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* The multiple "Capture Source" controls confuse alsamixer @@ -434,10 +445,11 @@ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + /* We don't use NID 0x07 - see above */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* The multiple "Capture Source" controls confuse alsamixer @@ -506,6 +518,8 @@ static snd_kcontrol_new_t alc880_z71v_mixer[] = { HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* The multiple "Capture Source" controls confuse alsamixer @@ -514,7 +528,7 @@ static snd_kcontrol_new_t alc880_z71v_mixer[] = { */ /* .name = "Capture Source", */ .name = "Input Source", - .count = 2, + .count = 3, .info = alc_mux_enum_info, .get = alc_mux_enum_get, .put = alc_mux_enum_put, @@ -564,8 +578,16 @@ static struct hda_verb alc880_init_verbs_three_stack[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* unmute amp left and right */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* set connection select to mic in */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute front mixer amp left (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, /* mute pin widget amp left and right (no gain on this amp) */ @@ -639,8 +661,16 @@ static struct hda_verb alc880_init_verbs_five_stack[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* unmute amp left and right */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* set connection select to mic in */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute front mixer amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, /* mute pin widget amp left and right (no gain on this amp) */ @@ -798,9 +828,16 @@ static struct hda_verb alc880_z71v_init_verbs[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* unmute amp left and right */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, - + /* set connection select to mic in */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer * widget(nid=0x0B) to support the input path of analog loopback */ @@ -941,7 +978,9 @@ static struct hda_pcm_stream alc880_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, - .nid = 0x07, /* NID to query formats and rates */ + .nid = 0x08, /* NID to query formats and rates + * (0x07 might be broken on some devices) + */ .ops = { .prepare = alc880_capture_pcm_prepare, .cleanup = alc880_capture_pcm_cleanup @@ -1261,6 +1300,13 @@ static struct hda_verb alc880_test_init_verbs[] = { {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* ADC set up */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, { } }; #endif @@ -1822,11 +1868,13 @@ static struct hda_verb alc882_init_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, /* ADC1: unmute amp left and right */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* ADC2: unmute amp left and right */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* ADC3: unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Unmute front loopback */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /* Unmute rear loopback */ -- cgit v0.10.2 From c3a9cfac750d78241b5dde7d004522f687703b90 Mon Sep 17 00:00:00 2001 From: Roger Mach Date: Thu, 26 May 2005 17:58:01 +0200 Subject: [ALSA] pcm_oss - fix SNDCTL_DSP_GETOPTR not working correctly ALSA<-OSS emulation This patch changes snd_pcm_oss_bytes() by adding a local variable for the frames -> bytes conversion, which means that the frame count is no longer corrupted by this conversion. Signed-off-by: Roger Mach Signed-off-by: Clemens Ladisch diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 6c8fdca..6f90dbb 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -124,11 +124,12 @@ int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin) static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) { + long bytes = 0; snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); - frames = frames_to_bytes(runtime, frames); + bytes = frames_to_bytes(runtime, frames); if (buffer_size == runtime->oss.buffer_bytes) - return frames; + return bytes; return (runtime->oss.buffer_bytes * frames) / buffer_size; } -- cgit v0.10.2 From 8e72ab349e54da49cf3e11480581a3e6704d9553 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 27 May 2005 10:07:06 +0200 Subject: [ALSA] Reverted last patch for SNDCTL_DSP_GETOPTR fix & possible overflow fix ALSA<-OSS emulation This reverts the last patch which wrongly mixes bytes and frames. The real culprit might be the 32-bit overflow, so the return expression uses 64-bit values now in snd_pcm_oss_bytes(). Signed-off-by: Jaroslav Kysela diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 6f90dbb..a293982 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -124,13 +124,12 @@ int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin) static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) { - long bytes = 0; snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); - bytes = frames_to_bytes(runtime, frames); + frames = frames_to_bytes(runtime, frames); if (buffer_size == runtime->oss.buffer_bytes) - return bytes; - return (runtime->oss.buffer_bytes * frames) / buffer_size; + return frames; + return (long)(((int64_t)runtime->oss.buffer_bytes * (int64_t)frames) / (int64_t)buffer_size); } static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) -- cgit v0.10.2 From fc232c6e8d618daae212f643587f33d202961861 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 10:42:45 +0200 Subject: [ALSA] Fix a wrong bit set in AC1985 code AC97 Codec Fixed a wrong bit set in AD1985 surround jack controls. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 5520f5d..b8106413 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1604,8 +1604,8 @@ static void ad1985_update_jacks(ac97_t *ac97) /* shared Mic */ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, is_shared_micin(ac97) ? 0 : 1 << 11); - snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 9 << 11, - is_shared_micin(ac97) ? 0 : 9 << 11); + snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 1 << 9, + is_shared_micin(ac97) ? 0 : 1 << 9); } static int patch_ad1985_specific(ac97_t *ac97) -- cgit v0.10.2 From 685c0dccadfe19233d414afd9f00b8d480a85953 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 11:10:18 +0200 Subject: [ALSA] Add dxs_support for a Twinhead mobo VIA82xx driver Added dxs_support=4 for a Twinhead mobo. Signed-off-by: Takashi Iwai diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 4c41df0..bb322de 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2179,6 +2179,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .vendor = 0x147b, .device = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */ { .vendor = 0x147b, .device = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ + { .vendor = 0x14ff, .device = 0x0408, .action = VIA_DXS_NO_VRA }, /* Twinhead mobo */ { .vendor = 0x1584, .device = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ { .vendor = 0x1584, .device = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ { .vendor = 0x161f, .device = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ -- cgit v0.10.2 From cdc27f3a3fad42f797d4112719d8455fda78c2df Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 11:11:02 +0200 Subject: [ALSA] [doc] Fix a comment about dxs_support for via82xx driver Documentation Fixed/improved a comment about dxs_support option for via82xx driver. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index bb31ae7..97544ef 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1286,8 +1286,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. sample rates (e.g. 44.1kHz of mp3 playback), please let us know the PCI subsystem vendor/device id's (output of "lspci -nv"). - If dxs_support=5 does not work, try dxs_support=1; if it - doesn't work too, try dxs_support=4. If it still doesn't + If dxs_support=5 does not work, try dxs_support=4; if it + doesn't work too, try dxs_support=1. (dxs_support=1 is + usually for old motherboards. The correct implementated + board should work with 4 or 5.) If it still doesn't work and the default setting is ok, dxs_support=3 is the right choice. If the default setting doesn't work at all, try dxs_support=2 to disable the DXS channels. -- cgit v0.10.2 From bfc5bddb8efb7e3d10e2f2e07dc2d68e808a9c68 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 27 May 2005 11:12:35 +0200 Subject: [ALSA] alsa-oss - improve readability of snd_pcm_oss_bytes() function ALSA<-OSS emulation Added bytes variable and do not use the frames argument as a temporaly storage for the byte counter. Signed-off-by: Jaroslav Kysela diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index a293982..b9deef9 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -126,10 +126,10 @@ static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); - frames = frames_to_bytes(runtime, frames); + long bytes = frames_to_bytes(runtime, frames); if (buffer_size == runtime->oss.buffer_bytes) - return frames; - return (long)(((int64_t)runtime->oss.buffer_bytes * (int64_t)frames) / (int64_t)buffer_size); + return bytes; + return (long)(((int64_t)runtime->oss.buffer_bytes * (int64_t)bytes) / (int64_t)buffer_size); } static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) -- cgit v0.10.2 From af0816139fcf926b6b5c3f866c509507b411d547 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 27 May 2005 11:15:20 +0200 Subject: [ALSA] alsa-oss - 2nd - improved readability ALSA<-OSS emulation Use 'long' for byte counters in snd_pcm_oss_bytes() snd_pcm_alsa_bytes(). Signed-off-by: Jaroslav Kysela diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index b9deef9..131522e 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -125,7 +125,7 @@ int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin) static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) { snd_pcm_runtime_t *runtime = substream->runtime; - snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); + long buffer_size = snd_pcm_lib_buffer_bytes(substream); long bytes = frames_to_bytes(runtime, frames); if (buffer_size == runtime->oss.buffer_bytes) return bytes; @@ -135,7 +135,7 @@ static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) { snd_pcm_runtime_t *runtime = substream->runtime; - snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); + long buffer_size = snd_pcm_lib_buffer_bytes(substream); if (buffer_size == runtime->oss.buffer_bytes) return bytes_to_frames(runtime, bytes); return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); -- cgit v0.10.2 From 11ca9afcfee3e6667a498b702642b09ac7312a8a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 11:34:34 +0200 Subject: [ALSA] als4000 - Fix kernel panic with MPU401 ALS4000 driver Fix kernel panic with als4000 when MPU401 is accessed. Signed-off-by: Takashi Iwai diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index cdc1134..ca28b22 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -367,7 +367,7 @@ static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs * if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */ snd_pcm_period_elapsed(chip->capture_substream); if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */ - snd_mpu401_uart_interrupt(irq, chip->rmidi, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); /* release the gcr */ outb(gcr_status, chip->alt_port + 0xe); -- cgit v0.10.2 From 8cfbbac6ad024c3dc749ff20d7c308794da6e370 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 12:10:40 +0200 Subject: [ALSA] ice1724 - Add support of Chaintech AV-710 Documentation,ICE1724 driver Add the support of Chaintech AV-710 to ice1724 driver. The patch includes the WM-codec initialization fix by Jaanus Kivistik . Since both AV-710 and AMP Audio2000 have the same SSID, initialize WM codecs as default for both devices. In case it breaks Audio2000, you can pass 'model=amp2000' option to avoid WM codec initialization. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 97544ef..2260130 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -733,11 +733,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * Chaintech ZNF3-150 * Chaintech ZNF3-250 * Chaintech 9CJS + * Chaintech AV-710 * Shuttle SN25P model - Use the given board model, one of the following: revo71, amp2000, prodigy71, prodigy192, aureon51, - aureon71, universe, k8x800, phase22, phase28, ms300 + aureon71, universe, k8x800, phase22, phase28, ms300, + av710 Module supports up to 8 cards and autoprobe. diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index 7799517..289b0b5 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c @@ -30,16 +30,39 @@ #include #include "ice1712.h" +#include "envy24ht.h" #include "amp.h" +static void wm_put(ice1712_t *ice, int reg, unsigned short val) +{ + unsigned short cval; + cval = (reg << 9) | val; + snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); +} static int __devinit snd_vt1724_amp_init(ice1712_t *ice) { + static unsigned short wm_inits[] = { + WM_ATTEN_L, 0x0000, /* 0 db */ + WM_ATTEN_R, 0x0000, /* 0 db */ + WM_DAC_CTRL, 0x0008, /* 24bit I2S */ + WM_INT_CTRL, 0x0001, /* 24bit I2S */ + }; + + unsigned int i; + /* only use basic functionality for now */ ice->num_total_dacs = 2; /* only PSDOUT0 is connected */ ice->num_total_adcs = 2; + /* Chaintech AV-710 has another codecs, which need initialization */ + /* initialize WM8728 codec */ + if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AV710) { + for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) + wm_put(ice, wm_inits[i], wm_inits[i+1]); + } + return 0; } @@ -54,6 +77,13 @@ static int __devinit snd_vt1724_amp_add_controls(ice1712_t *ice) /* entry point */ struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = { { + .subvendor = VT1724_SUBDEVICE_AV710, + .name = "Chaintech AV-710", + .model = "av710", + .chip_init = snd_vt1724_amp_init, + .build_controls = snd_vt1724_amp_add_controls, + }, + { .subvendor = VT1724_SUBDEVICE_AUDIO2000, .name = "AMP Ltd AUDIO2000", .model = "amp2000", diff --git a/sound/pci/ice1712/amp.h b/sound/pci/ice1712/amp.h index d58d433..a0fc89b 100644 --- a/sound/pci/ice1712/amp.h +++ b/sound/pci/ice1712/amp.h @@ -24,9 +24,23 @@ * */ -#define AMP_AUDIO2000_DEVICE_DESC "{AMP Ltd,AUDIO2000}," +#define AMP_AUDIO2000_DEVICE_DESC "{AMP Ltd,AUDIO2000},"\ + "{Chaintech,AV-710}," +#if 0 #define VT1724_SUBDEVICE_AUDIO2000 0x12142417 /* Advanced Micro Peripherals Ltd AUDIO2000 */ +#else +#define VT1724_SUBDEVICE_AUDIO2000 0x00030003 /* a dummy ID for AMP Audio2000 */ +#endif +#define VT1724_SUBDEVICE_AV710 0x12142417 /* AV710 - the same ID with Audio2000! */ + +/* WM8728 on I2C for AV710 */ +#define WM_DEV 0x36 + +#define WM_ATTEN_L 0x00 +#define WM_ATTEN_R 0x01 +#define WM_DAC_CTRL 0x02 +#define WM_INT_CTRL 0x03 extern struct snd_ice1712_card_info snd_vt1724_amp_cards[]; -- cgit v0.10.2 From a6c17ec89d33a714b3e94a252c127f2ff63363c8 Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Fri, 27 May 2005 12:31:34 +0200 Subject: [ALSA] emu10k1: add details for the audigy player box version EMU10K1/EMU10K2 driver Add details for the audigy player box version. Signed-off-by: Arnaud Patard Signed-off-by: Takashi Iwai diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 070be6a..77be072 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -700,6 +700,12 @@ static emu_chip_details_t emu_chip_details[] = { .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102, + .driver = "Audigy", .name = "Audigy 1 [SB0090]", + .id = "Audigy", + .emu10k2_chip = 1, + .ca0102_chip = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .driver = "Audigy", .name = "Audigy 1 [Unknown]", .id = "Audigy", -- cgit v0.10.2 From cdc5c53fde266055debf7f5c9c043d5acf47c5ff Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 12:40:52 +0200 Subject: [ALSA] Fix compilation on 32bit arch ALSA<-OSS emulation Fix the division with int64 for 32bit architectures. Signed-off-by: Takashi Iwai diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 131522e..468fca8 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -129,7 +129,16 @@ static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) long bytes = frames_to_bytes(runtime, frames); if (buffer_size == runtime->oss.buffer_bytes) return bytes; - return (long)(((int64_t)runtime->oss.buffer_bytes * (int64_t)bytes) / (int64_t)buffer_size); +#if BITS_PER_LONG >= 64 + return runtime->oss.buffer_bytes * bytes / buffer_size; +#else + { + u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes; + u32 rem; + div64_32(&bsize, buffer_size, &rem); + return (long)bsize; + } +#endif } static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) -- cgit v0.10.2 From 7028b09eecf01549ccaee9c884f48e5e00ec3d65 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 27 May 2005 12:42:26 +0200 Subject: [ALSA] select ISAPNP for SND_INTERWAVE_STB target ISA Signed-off-by: Jaroslav Kysela diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 3a3228b..148a856 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -179,6 +179,7 @@ config SND_INTERWAVE_STB select SND_RAWMIDI select SND_CS4231_LIB select SND_GUS_SYNTH + select ISAPNP help Say Y here to include support for AMD InterWave based soundcards with a TEA6330T bass and treble regulator -- cgit v0.10.2 From bbc0274e9bb2e3f1d724d445a2bd32566b9b66f7 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 29 May 2005 10:32:48 +0200 Subject: [ALSA] version 1.0.9 diff --git a/include/sound/version.h b/include/sound/version.h index f5959de..46acfa8 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h. Generated by configure. */ -#define CONFIG_SND_VERSION "1.0.9rc3" -#define CONFIG_SND_DATE " (Thu Mar 24 10:33:39 2005 UTC)" +#define CONFIG_SND_VERSION "1.0.9" +#define CONFIG_SND_DATE " (Sun May 29 07:31:02 2005 UTC)" -- cgit v0.10.2 From c2731509cfb538b9b38feaf657fab2334ea45253 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Thu, 2 Jun 2005 12:18:20 -0500 Subject: JFS: kernel BUG at fs/jfs/jfs_txnmgr.c:859 add_missing_indices() must set tlck->type to tlckBTROOT when modifying a root btree root to avoid a trap in txRelease() Signed-off-by: Dave Kleikamp diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index ac41f72..8676aee 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -2931,6 +2931,9 @@ static void add_missing_indices(struct inode *inode, s64 bn) ASSERT(p->header.flag & BT_LEAF); tlck = txLock(tid, inode, mp, tlckDTREE | tlckENTRY); + if (BT_IS_ROOT(mp)) + tlck->type |= tlckBTROOT; + dtlck = (struct dt_lock *) &tlck->lock; stbl = DT_GETSTBL(p); -- cgit v0.10.2 From 72e3148a6e987974e3e949c5668e5ca812d7c818 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Fri, 3 Jun 2005 14:09:54 -0500 Subject: JFS: Fix compiler warning in jfs_logmgr.c fs/jfs/jfs_logmgr.c: In function `jfs_flush_journal': fs/jfs/jfs_logmgr.c:1632: warning: unused variable `mp' Some debug code in jfs_flush_journal does nothing when CONFIG_JFS_DEBUG is not defined. Place the whole code segment within an ifdef to avoid unnecessary code to be compiled and the warning to be issued. Signed-off-by: Dave Kleikamp diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index c5cc03b..7c8387e 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -1617,6 +1617,8 @@ void jfs_flush_journal(struct jfs_log *log, int wait) } } assert(list_empty(&log->cqueue)); + +#ifdef CONFIG_JFS_DEBUG if (!list_empty(&log->synclist)) { struct logsyncblk *lp; @@ -1631,9 +1633,8 @@ void jfs_flush_journal(struct jfs_log *log, int wait) dump_mem("orphan tblock", lp, sizeof(struct tblock)); } -// current->state = TASK_INTERRUPTIBLE; -// schedule(); } +#endif //assert(list_empty(&log->synclist)); clear_bit(log_FLUSH, &log->flag); } -- cgit v0.10.2 From 986a80d5c154808cc78170584670324a22fd8219 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 16 Jun 2005 15:14:00 -0700 Subject: [PATCH] avoid signed vs unsigned comparison in efi_range_is_wc() warning when building with gcc -W : include/linux/efi.h: In function `efi_range_is_wc': include/linux/efi.h:320: warning: comparison between signed and unsigned It looks to me like a significantly large 'len' passed in could cause the loop to never end. Isn't it safer to make 'i' an unsigned long as well? Like this little patch below (which of course also kills the warning) : Signed-off-by: Jesper Juhl Signed-off-by: Tony Luck diff --git a/include/linux/efi.h b/include/linux/efi.h index 047e722..73781ec 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -315,7 +315,7 @@ extern struct efi_memory_map memmap; */ static inline int efi_range_is_wc(unsigned long start, unsigned long len) { - int i; + unsigned long i; for (i = 0; i < len; i += (1UL << EFI_PAGE_SHIFT)) { unsigned long paddr = __pa(start + i); -- cgit v0.10.2 From 0908db22b189b28664cba3965ebb7e0df59c749a Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 19 Jun 2005 19:48:16 +0100 Subject: [PATCH] ARM SMP: Messages about CPUs should be prefixed by CPU%u Signed-off-by: Russell King diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 45ed036..3489275 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -145,7 +145,8 @@ int __init __cpu_up(unsigned int cpu) pgd_free(pgd); if (ret) { - printk(KERN_CRIT "cpu_up: processor %d failed to boot\n", cpu); + printk(KERN_CRIT "CPU%u: processor failed to boot\n", cpu); + /* * FIXME: We need to clean up the new idle thread. --rmk */ -- cgit v0.10.2 From 98f72a1c51cbf65f3eee54b5324863b3a70a4e61 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 19 Jun 2005 21:47:56 -0400 Subject: fc4/fc: fix warnings and errors related to recent SCSI EH updates diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c index fbd9ff7..e3c9588 100644 --- a/drivers/fc4/fc.c +++ b/drivers/fc4/fc.c @@ -765,8 +765,6 @@ void fcp_release(fc_channel *fcchain, int count) /* count must > 0 */ static void fcp_scsi_done (Scsi_Cmnd *SCpnt) { - unsigned long flags; - if (FCP_CMND(SCpnt)->done) FCP_CMND(SCpnt)->done(SCpnt); } @@ -907,8 +905,6 @@ int fcp_scsi_abort(Scsi_Cmnd *SCpnt) */ if (++fc->abort_count < (fc->can_queue >> 1)) { - unsigned long flags; - SCpnt->result = DID_ABORT; fcmd->done(SCpnt); printk("FC: soft abort\n"); @@ -931,6 +927,7 @@ void fcp_scsi_reset_done(Scsi_Cmnd *SCpnt) int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt) { + unsigned long flags; fcp_cmd *cmd; fcp_cmnd *fcmd; fc_channel *fc = FC_SCMND(SCpnt); @@ -1028,6 +1025,7 @@ static int __fcp_scsi_host_reset(Scsi_Cmnd *SCpnt) int fcp_scsi_host_reset(Scsi_Cmnd *SCpnt) { + unsigned long flags; int rc; spin_lock_irqsave(SCpnt->device->host->host_lock, flags); -- cgit v0.10.2 From e632ba11b8ea34cc877689dba1e02f8657ddbc0b Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 19 Jun 2005 21:50:12 -0400 Subject: aic7xxx/aic79xx_osm: revert completely bogus ahd_linux_queue() patch diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index c4eaaad..5f526dd 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -941,7 +941,7 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) */ cmd->scsi_done = scsi_done; - ahd_lock(ahd, &flags); + ahd_midlayer_entrypoint_lock(ahd, &flags); /* * Close the race of a command that was in the process of @@ -955,7 +955,7 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); ahd_linux_queue_cmd_complete(ahd, cmd); ahd_schedule_completeq(ahd); - ahd_unlock(ahd, &flags); + ahd_midlayer_entrypoint_unlock(ahd, &flags); return (0); } dev = ahd_linux_get_device(ahd, cmd->device->channel, @@ -965,7 +965,7 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); ahd_linux_queue_cmd_complete(ahd, cmd); ahd_schedule_completeq(ahd); - ahd_unlock(ahd, &flags); + ahd_midlayer_entrypoint_unlock(ahd, &flags); printf("%s: aic79xx_linux_queue - Unable to allocate device!\n", ahd_name(ahd)); return (0); @@ -979,7 +979,7 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) dev->flags |= AHD_DEV_ON_RUN_LIST; ahd_linux_run_device_queues(ahd); } - ahd_unlock(ahd, &flags); + ahd_midlayer_entrypoint_unlock(ahd, &flags); return (0); } -- cgit v0.10.2 From 8830f04a092b47f3d246271b24685cd9eab82027 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Jun 2005 09:51:03 +0100 Subject: [PATCH] ARM: Fix delayed dcache flush for ARMv6 non-aliasing caches flush_dcache_page() did nothing for these caches, but since they suffer from I/D cache coherency issues, we need to ensure that data is written back to RAM. Signed-off-by: Russell King diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 01967dd..be4ab3d 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -77,9 +77,8 @@ no_pmd: } static void -make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty) +make_coherent(struct address_space *mapping, struct vm_area_struct *vma, unsigned long addr, unsigned long pfn) { - struct address_space *mapping = page_mapping(page); struct mm_struct *mm = vma->vm_mm; struct vm_area_struct *mpnt; struct prio_tree_iter iter; @@ -87,9 +86,6 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, pgoff_t pgoff; int aliases = 0; - if (!mapping) - return; - pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT); /* @@ -115,9 +111,11 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, if (aliases) adjust_pte(vma, addr); else - flush_cache_page(vma, addr, page_to_pfn(page)); + flush_cache_page(vma, addr, pfn); } +void __flush_dcache_page(struct address_space *mapping, struct page *page); + /* * Take care of architecture specific things when placing a new PTE into * a page table, or changing an existing PTE. Basically, there are two @@ -134,29 +132,22 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) { unsigned long pfn = pte_pfn(pte); + struct address_space *mapping; struct page *page; if (!pfn_valid(pfn)) return; + page = pfn_to_page(pfn); - if (page_mapping(page)) { + mapping = page_mapping(page); + if (mapping) { int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); - if (dirty) { - /* - * This is our first userspace mapping of this page. - * Ensure that the physical page is coherent with - * the kernel mapping. - * - * FIXME: only need to do this on VIVT and aliasing - * VIPT cache architectures. We can do that - * by choosing whether to set this bit... - */ - __cpuc_flush_dcache_page(page_address(page)); - } + if (dirty) + __flush_dcache_page(mapping, page); if (cache_is_vivt()) - make_coherent(vma, addr, page, dirty); + make_coherent(mapping, vma, addr, pfn); } } diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 4085ed9..191788f 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -37,13 +37,8 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) #define flush_pfn_alias(pfn,vaddr) do { } while (0) #endif -static void __flush_dcache_page(struct address_space *mapping, struct page *page) +void __flush_dcache_page(struct address_space *mapping, struct page *page) { - struct mm_struct *mm = current->active_mm; - struct vm_area_struct *mpnt; - struct prio_tree_iter iter; - pgoff_t pgoff; - /* * Writeback any data associated with the kernel mapping of this * page. This ensures that data in the physical page is mutually @@ -52,24 +47,21 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page __cpuc_flush_dcache_page(page_address(page)); /* - * If there's no mapping pointer here, then this page isn't - * visible to userspace yet, so there are no cache lines - * associated with any other aliases. - */ - if (!mapping) - return; - - /* - * This is a page cache page. If we have a VIPT cache, we - * only need to do one flush - which would be at the relevant + * If this is a page cache page, and we have an aliasing VIPT cache, + * we only need to do one flush - which would be at the relevant * userspace colour, which is congruent with page->index. */ - if (cache_is_vipt()) { - if (cache_is_vipt_aliasing()) - flush_pfn_alias(page_to_pfn(page), - page->index << PAGE_CACHE_SHIFT); - return; - } + if (mapping && cache_is_vipt_aliasing()) + flush_pfn_alias(page_to_pfn(page), + page->index << PAGE_CACHE_SHIFT); +} + +static void __flush_dcache_aliases(struct address_space *mapping, struct page *page) +{ + struct mm_struct *mm = current->active_mm; + struct vm_area_struct *mpnt; + struct prio_tree_iter iter; + pgoff_t pgoff; /* * There are possible user space mappings of this page: @@ -116,12 +108,12 @@ void flush_dcache_page(struct page *page) { struct address_space *mapping = page_mapping(page); - if (cache_is_vipt_nonaliasing()) - return; - if (mapping && !mapping_mapped(mapping)) set_bit(PG_dcache_dirty, &page->flags); - else + else { __flush_dcache_page(mapping, page); + if (mapping && cache_is_vivt()) + __flush_dcache_aliases(mapping, page); + } } EXPORT_SYMBOL(flush_dcache_page); -- cgit v0.10.2 From b8a9b66fbee09d0cc71c272b5c1d1f3320afbbf0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Jun 2005 11:31:09 +0100 Subject: [PATCH] ARM: Add common CACHE_COLOUR macro Signed-off-by: Russell King diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index a8c0023..27d0415 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -30,8 +30,6 @@ static DEFINE_SPINLOCK(v6_lock); -#define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) - /* * Copy the user page. No aliasing to deal with so we can just * attack the kernel's existing mapping of these pages. @@ -55,7 +53,7 @@ void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr) */ void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr) { - unsigned int offset = DCACHE_COLOUR(vaddr); + unsigned int offset = CACHE_COLOUR(vaddr); unsigned long from, to; /* @@ -95,7 +93,7 @@ void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vadd */ void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr) { - unsigned int offset = DCACHE_COLOUR(vaddr); + unsigned int offset = CACHE_COLOUR(vaddr); unsigned long to = to_address + (offset << PAGE_SHIFT); /* diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h index 09ffeed..035cdcf 100644 --- a/include/asm-arm/cacheflush.h +++ b/include/asm-arm/cacheflush.h @@ -16,6 +16,9 @@ #include #include +#include + +#define CACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) /* * Cache Model -- cgit v0.10.2 From 5abc100e882a979f8f5be8184938305b3fb2df2b Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Jun 2005 12:31:14 +0100 Subject: [PATCH] ARM: Ensure DMA-bounced buffers are properly written to RAM When DMA bounce buffers were unmapped and the data was memcpy'd to the original buffer, we were not ensuring that the data was written to RAM. This means that there was the potential for page cache pages to have different cache states depending whether they've been bounced or not. Signed-off-by: Russell King diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 5797b1b..39dd33f 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -302,12 +302,24 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, DO_STATS ( device_info->bounce_count++ ); - if ((dir == DMA_FROM_DEVICE) || - (dir == DMA_BIDIRECTIONAL)) { + if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { + unsigned long ptr; + dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", __func__, buf->safe, buf->ptr, size); memcpy(buf->ptr, buf->safe, size); + + /* + * DMA buffers must have the same cache properties + * as if they were really used for DMA - which means + * data must be written back to RAM. Note that + * we don't use dmac_flush_range() here for the + * bidirectional case because we know the cache + * lines will be coherent with the data written. + */ + ptr = (unsigned long)buf->ptr; + dmac_clean_range(ptr, ptr + size); } free_safe_buffer(device_info, buf); } -- cgit v0.10.2 From ad21798e0ecc3b54720a2420b341f51dfb254706 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 20 Jun 2005 21:43:07 +1000 Subject: [PATCH] ppc64: quieten RTAS printks Some rtasd printks were too loud. They would appear on a quiet boot even though they were only informational. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras diff --git a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c index ff65dc3..b0c3b82 100644 --- a/arch/ppc64/kernel/rtasd.c +++ b/arch/ppc64/kernel/rtasd.c @@ -440,7 +440,7 @@ static int rtasd(void *unused) goto error; } - printk(KERN_ERR "RTAS daemon started\n"); + printk(KERN_INFO "RTAS daemon started\n"); DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2); @@ -485,7 +485,7 @@ static int __init rtas_init(void) /* No RTAS, only warn if we are on a pSeries box */ if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) { if (systemcfg->platform & PLATFORM_PSERIES) - printk(KERN_ERR "rtasd: no event-scan on system\n"); + printk(KERN_INFO "rtasd: no event-scan on system\n"); return 1; } -- cgit v0.10.2 From 0231c290d817513d448963520a97eadd51a370b7 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 20 Jun 2005 21:43:15 +1000 Subject: [PATCH] ppc64: use cpu_has_feature macro Use the new cpu_has_feature macros instead of open coding it. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index fbad349..4203bd0 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c @@ -375,7 +375,7 @@ static int smp_pSeries_cpu_bootable(unsigned int nr) * cpus are assumed to be secondary threads. */ if (system_state < SYSTEM_RUNNING && - cur_cpu_spec->cpu_features & CPU_FTR_SMT && + cpu_has_feature(CPU_FTR_SMT) && !smt_enabled_at_boot && nr % 2 != 0) return 0; @@ -419,8 +419,8 @@ void __init smp_init_pSeries(void) #endif /* Mark threads which are still spinning in hold loops. */ - if (cur_cpu_spec->cpu_features & CPU_FTR_SMT) - for_each_present_cpu(i) { + if (cpu_has_feature(CPU_FTR_SMT)) { + for_each_present_cpu(i) { if (i % 2 == 0) /* * Even-numbered logical cpus correspond to @@ -428,8 +428,9 @@ void __init smp_init_pSeries(void) */ cpu_set(i, of_spin_map); } - else + } else { of_spin_map = cpu_present_map; + } cpu_clear(boot_cpuid, of_spin_map); -- cgit v0.10.2 From d3588ba9bbade7f1fde59726c9af43eeeb08e092 Mon Sep 17 00:00:00 2001 From: John Rose Date: Mon, 20 Jun 2005 21:43:48 +1000 Subject: [PATCH] initialize TCE tables A fairly recent platform requirement states that the OS must clear the whole TCE table at setup time, in case firmware left any active mappings in it. Without this initialization, dynamic bus removes can fail. Firmware rejects these requests if active mappings still exist for a slot that has been deallocated by the OS. Signed-off-by: John Rose Signed-off-by: Paul Mackerras diff --git a/arch/ppc64/kernel/iommu.c b/arch/ppc64/kernel/iommu.c index 3441646..8316426 100644 --- a/arch/ppc64/kernel/iommu.c +++ b/arch/ppc64/kernel/iommu.c @@ -423,6 +423,9 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl) tbl->it_largehint = tbl->it_halfpoint; spin_lock_init(&tbl->it_lock); + /* Clear the hardware table in case firmware left allocations in it */ + ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); + if (!welcomed) { printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n", novmerge ? "disabled" : "enabled"); -- cgit v0.10.2 From 34c8eacab670e578a2aaafdf1061efd214b2f639 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Jun 2005 12:56:40 +0100 Subject: [PATCH] ARM: Remove obsolete arch/arm/kernel/arch.c This is not used anymore - RiscPC now contains the necessary supporting code. Signed-off-by: Russell King diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 4a2af55..3e1b032 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -6,7 +6,7 @@ AFLAGS_head.o := -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) # Object file lists. -obj-y := arch.o compat.o dma.o entry-armv.o entry-common.o irq.o \ +obj-y := compat.o dma.o entry-armv.o entry-common.o irq.o \ process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ time.o traps.o diff --git a/arch/arm/kernel/arch.c b/arch/arm/kernel/arch.c deleted file mode 100644 index 4e02fbe..0000000 --- a/arch/arm/kernel/arch.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * linux/arch/arm/kernel/arch.c - * - * Architecture specific fixups. - */ -#include -#include -#include - -#include -#include -#include -#include - -unsigned int vram_size; - -#ifdef CONFIG_ARCH_ACORN - -unsigned int memc_ctrl_reg; -unsigned int number_mfm_drives; - -static int __init parse_tag_acorn(const struct tag *tag) -{ - memc_ctrl_reg = tag->u.acorn.memc_control_reg; - number_mfm_drives = tag->u.acorn.adfsdrives; - - switch (tag->u.acorn.vram_pages) { - case 512: - vram_size += PAGE_SIZE * 256; - case 256: - vram_size += PAGE_SIZE * 256; - default: - break; - } -#if 0 - if (vram_size) { - desc->video_start = 0x02000000; - desc->video_end = 0x02000000 + vram_size; - } -#endif - return 0; -} - -__tagtable(ATAG_ACORN, parse_tag_acorn); - -#endif -- cgit v0.10.2 From f29481c0e7e55efc25598c1a6c503015cfe45245 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Jun 2005 15:49:59 +0100 Subject: [PATCH] ARM: Remove gcc type-isms from GCC helper functions Convert ugly GCC types to Linux types: UQImode -> u8 SImode -> s32 USImode -> u32 DImode -> s64 UDImode -> u64 word_type -> int Signed-off-by: Russell King diff --git a/arch/arm/lib/ashldi3.c b/arch/arm/lib/ashldi3.c index 130f5a8..02d2b62 100644 --- a/arch/arm/lib/ashldi3.c +++ b/arch/arm/lib/ashldi3.c @@ -31,11 +31,11 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -DItype -__ashldi3 (DItype u, word_type b) +s64 +__ashldi3 (s64 u, int b) { DIunion w; - word_type bm; + int bm; DIunion uu; if (b == 0) @@ -43,17 +43,17 @@ __ashldi3 (DItype u, word_type b) uu.ll = u; - bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + bm = (sizeof (s32) * BITS_PER_UNIT) - b; if (bm <= 0) { w.s.low = 0; - w.s.high = (USItype)uu.s.low << -bm; + w.s.high = (u32)uu.s.low << -bm; } else { - USItype carries = (USItype)uu.s.low >> bm; - w.s.low = (USItype)uu.s.low << b; - w.s.high = ((USItype)uu.s.high << b) | carries; + u32 carries = (u32)uu.s.low >> bm; + w.s.low = (u32)uu.s.low << b; + w.s.high = ((u32)uu.s.high << b) | carries; } return w.ll; diff --git a/arch/arm/lib/ashrdi3.c b/arch/arm/lib/ashrdi3.c index 71625d2..89f6fb7 100644 --- a/arch/arm/lib/ashrdi3.c +++ b/arch/arm/lib/ashrdi3.c @@ -31,11 +31,11 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -DItype -__ashrdi3 (DItype u, word_type b) +s64 +__ashrdi3 (s64 u, int b) { DIunion w; - word_type bm; + int bm; DIunion uu; if (b == 0) @@ -43,18 +43,18 @@ __ashrdi3 (DItype u, word_type b) uu.ll = u; - bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + bm = (sizeof (s32) * BITS_PER_UNIT) - b; if (bm <= 0) { /* w.s.high = 1..1 or 0..0 */ - w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1); + w.s.high = uu.s.high >> (sizeof (s32) * BITS_PER_UNIT - 1); w.s.low = uu.s.high >> -bm; } else { - USItype carries = (USItype)uu.s.high << bm; + u32 carries = (u32)uu.s.high << bm; w.s.high = uu.s.high >> b; - w.s.low = ((USItype)uu.s.low >> b) | carries; + w.s.low = ((u32)uu.s.low >> b) | carries; } return w.ll; diff --git a/arch/arm/lib/gcclib.h b/arch/arm/lib/gcclib.h index 65314a3..283f529 100644 --- a/arch/arm/lib/gcclib.h +++ b/arch/arm/lib/gcclib.h @@ -1,25 +1,20 @@ /* gcclib.h -- definitions for various functions 'borrowed' from gcc-2.95.3 */ /* I Molton 29/07/01 */ -#define BITS_PER_UNIT 8 -#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT) +#include -typedef unsigned int UQItype __attribute__ ((mode (QI))); -typedef int SItype __attribute__ ((mode (SI))); -typedef unsigned int USItype __attribute__ ((mode (SI))); -typedef int DItype __attribute__ ((mode (DI))); -typedef int word_type __attribute__ ((mode (__word__))); -typedef unsigned int UDItype __attribute__ ((mode (DI))); +#define BITS_PER_UNIT 8 +#define SI_TYPE_SIZE (sizeof(s32) * BITS_PER_UNIT) #ifdef __ARMEB__ - struct DIstruct {SItype high, low;}; + struct DIstruct {s32 high, low;}; #else - struct DIstruct {SItype low, high;}; + struct DIstruct {s32 low, high;}; #endif typedef union { struct DIstruct s; - DItype ll; + s64 ll; } DIunion; diff --git a/arch/arm/lib/longlong.h b/arch/arm/lib/longlong.h index 179eea4..3ef7695 100644 --- a/arch/arm/lib/longlong.h +++ b/arch/arm/lib/longlong.h @@ -26,18 +26,18 @@ #define __BITS4 (SI_TYPE_SIZE / 4) #define __ll_B (1L << (SI_TYPE_SIZE / 2)) -#define __ll_lowpart(t) ((USItype) (t) % __ll_B) -#define __ll_highpart(t) ((USItype) (t) / __ll_B) +#define __ll_lowpart(t) ((u32) (t) % __ll_B) +#define __ll_highpart(t) ((u32) (t) / __ll_B) /* Define auxiliary asm macros. 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) - multiplies two USItype integers MULTIPLER and MULTIPLICAND, - and generates a two-part USItype product in HIGH_PROD and + multiplies two u32 integers MULTIPLER and MULTIPLICAND, + and generates a two-part u32 product in HIGH_PROD and LOW_PROD. - 2) __umulsidi3(a,b) multiplies two USItype integers A and B, - and returns a UDItype product. This is just a variant of umul_ppmm. + 2) __umulsidi3(a,b) multiplies two u32 integers A and B, + and returns a u64 product. This is just a variant of umul_ppmm. 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, denominator) divides a two-word unsigned integer, composed by the @@ -77,23 +77,23 @@ #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("adds %1, %4, %5 \n\ adc %0, %2, %3" \ - : "=r" ((USItype) (sh)), \ - "=&r" ((USItype) (sl)) \ - : "%r" ((USItype) (ah)), \ - "rI" ((USItype) (bh)), \ - "%r" ((USItype) (al)), \ - "rI" ((USItype) (bl))) + : "=r" ((u32) (sh)), \ + "=&r" ((u32) (sl)) \ + : "%r" ((u32) (ah)), \ + "rI" ((u32) (bh)), \ + "%r" ((u32) (al)), \ + "rI" ((u32) (bl))) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ __asm__ ("subs %1, %4, %5 \n\ sbc %0, %2, %3" \ - : "=r" ((USItype) (sh)), \ - "=&r" ((USItype) (sl)) \ - : "r" ((USItype) (ah)), \ - "rI" ((USItype) (bh)), \ - "r" ((USItype) (al)), \ - "rI" ((USItype) (bl))) + : "=r" ((u32) (sh)), \ + "=&r" ((u32) (sl)) \ + : "r" ((u32) (ah)), \ + "rI" ((u32) (bh)), \ + "r" ((u32) (al)), \ + "rI" ((u32) (bl))) #define umul_ppmm(xh, xl, a, b) \ -{register USItype __t0, __t1, __t2; \ +{register u32 __t0, __t1, __t2; \ __asm__ ("%@ Inlined umul_ppmm \n\ mov %2, %5, lsr #16 \n\ mov %0, %6, lsr #16 \n\ @@ -107,11 +107,11 @@ addcs %0, %0, #65536 \n\ adds %1, %1, %3, lsl #16 \n\ adc %0, %0, %3, lsr #16" \ - : "=&r" ((USItype) (xh)), \ - "=r" ((USItype) (xl)), \ + : "=&r" ((u32) (xh)), \ + "=r" ((u32) (xl)), \ "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ - : "r" ((USItype) (a)), \ - "r" ((USItype) (b)));} + : "r" ((u32) (a)), \ + "r" ((u32) (b)));} #define UMUL_TIME 20 #define UDIV_TIME 100 #endif /* __arm__ */ @@ -123,14 +123,14 @@ #define __udiv_qrnnd_c(q, r, n1, n0, d) \ do { \ - USItype __d1, __d0, __q1, __q0; \ - USItype __r1, __r0, __m; \ + u32 __d1, __d0, __q1, __q0; \ + u32 __r1, __r0, __m; \ __d1 = __ll_highpart (d); \ __d0 = __ll_lowpart (d); \ \ __r1 = (n1) % __d1; \ __q1 = (n1) / __d1; \ - __m = (USItype) __q1 * __d0; \ + __m = (u32) __q1 * __d0; \ __r1 = __r1 * __ll_B | __ll_highpart (n0); \ if (__r1 < __m) \ { \ @@ -143,7 +143,7 @@ \ __r0 = __r1 % __d1; \ __q0 = __r1 / __d1; \ - __m = (USItype) __q0 * __d0; \ + __m = (u32) __q0 * __d0; \ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ if (__r0 < __m) \ { \ @@ -154,7 +154,7 @@ } \ __r0 -= __m; \ \ - (q) = (USItype) __q1 * __ll_B | __q0; \ + (q) = (u32) __q1 * __ll_B | __q0; \ (r) = __r0; \ } while (0) @@ -163,14 +163,14 @@ #define count_leading_zeros(count, x) \ do { \ - USItype __xr = (x); \ - USItype __a; \ + u32 __xr = (x); \ + u32 __a; \ \ if (SI_TYPE_SIZE <= 32) \ { \ - __a = __xr < ((USItype)1<<2*__BITS4) \ - ? (__xr < ((USItype)1<<__BITS4) ? 0 : __BITS4) \ - : (__xr < ((USItype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ + __a = __xr < ((u32)1<<2*__BITS4) \ + ? (__xr < ((u32)1<<__BITS4) ? 0 : __BITS4) \ + : (__xr < ((u32)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ } \ else \ { \ diff --git a/arch/arm/lib/lshrdi3.c b/arch/arm/lib/lshrdi3.c index b666f1b..5c2385a 100644 --- a/arch/arm/lib/lshrdi3.c +++ b/arch/arm/lib/lshrdi3.c @@ -31,11 +31,11 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -DItype -__lshrdi3 (DItype u, word_type b) +s64 +__lshrdi3 (s64 u, int b) { DIunion w; - word_type bm; + int bm; DIunion uu; if (b == 0) @@ -43,17 +43,17 @@ __lshrdi3 (DItype u, word_type b) uu.ll = u; - bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + bm = (sizeof (s32) * BITS_PER_UNIT) - b; if (bm <= 0) { w.s.high = 0; - w.s.low = (USItype)uu.s.high >> -bm; + w.s.low = (u32)uu.s.high >> -bm; } else { - USItype carries = (USItype)uu.s.high << bm; - w.s.high = (USItype)uu.s.high >> b; - w.s.low = ((USItype)uu.s.low >> b) | carries; + u32 carries = (u32)uu.s.high << bm; + w.s.high = (u32)uu.s.high >> b; + w.s.low = ((u32)uu.s.low >> b) | carries; } return w.ll; diff --git a/arch/arm/lib/muldi3.c b/arch/arm/lib/muldi3.c index 44d611b..5b649fa 100644 --- a/arch/arm/lib/muldi3.c +++ b/arch/arm/lib/muldi3.c @@ -32,7 +32,7 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" #define umul_ppmm(xh, xl, a, b) \ -{register USItype __t0, __t1, __t2; \ +{register u32 __t0, __t1, __t2; \ __asm__ ("%@ Inlined umul_ppmm \n\ mov %2, %5, lsr #16 \n\ mov %0, %6, lsr #16 \n\ @@ -46,11 +46,11 @@ Boston, MA 02111-1307, USA. */ addcs %0, %0, #65536 \n\ adds %1, %1, %3, lsl #16 \n\ adc %0, %0, %3, lsr #16" \ - : "=&r" ((USItype) (xh)), \ - "=r" ((USItype) (xl)), \ + : "=&r" ((u32) (xh)), \ + "=r" ((u32) (xl)), \ "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ - : "r" ((USItype) (a)), \ - "r" ((USItype) (b)));} + : "r" ((u32) (a)), \ + "r" ((u32) (b)));} #define __umulsidi3(u, v) \ @@ -59,8 +59,8 @@ Boston, MA 02111-1307, USA. */ __w.ll; }) -DItype -__muldi3 (DItype u, DItype v) +s64 +__muldi3 (s64 u, s64 v) { DIunion w; DIunion uu, vv; @@ -69,8 +69,8 @@ __muldi3 (DItype u, DItype v) vv.ll = v; w.ll = __umulsidi3 (uu.s.low, vv.s.low); - w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high - + (USItype) uu.s.high * (USItype) vv.s.low); + w.s.high += ((u32) uu.s.low * (u32) vv.s.high + + (u32) uu.s.high * (u32) vv.s.low); return w.ll; } diff --git a/arch/arm/lib/ucmpdi2.c b/arch/arm/lib/ucmpdi2.c index 6c6ae63..3eb438c 100644 --- a/arch/arm/lib/ucmpdi2.c +++ b/arch/arm/lib/ucmpdi2.c @@ -31,20 +31,20 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -word_type -__ucmpdi2 (DItype a, DItype b) +int +__ucmpdi2 (s64 a, s64 b) { DIunion au, bu; au.ll = a, bu.ll = b; - if ((USItype) au.s.high < (USItype) bu.s.high) + if ((u32) au.s.high < (u32) bu.s.high) return 0; - else if ((USItype) au.s.high > (USItype) bu.s.high) + else if ((u32) au.s.high > (u32) bu.s.high) return 2; - if ((USItype) au.s.low < (USItype) bu.s.low) + if ((u32) au.s.low < (u32) bu.s.low) return 0; - else if ((USItype) au.s.low > (USItype) bu.s.low) + else if ((u32) au.s.low > (u32) bu.s.low) return 2; return 1; } diff --git a/arch/arm/lib/udivdi3.c b/arch/arm/lib/udivdi3.c index d25195f..df1d5ef 100644 --- a/arch/arm/lib/udivdi3.c +++ b/arch/arm/lib/udivdi3.c @@ -32,7 +32,7 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" #include "longlong.h" -static const UQItype __clz_tab[] = +static const u8 __clz_tab[] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, @@ -44,15 +44,15 @@ static const UQItype __clz_tab[] = 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, }; -UDItype -__udivmoddi4 (UDItype n, UDItype d, UDItype *rp) +u64 +__udivmoddi4 (u64 n, u64 d, u64 *rp) { DIunion ww; DIunion nn, dd; DIunion rr; - USItype d0, d1, n0, n1, n2; - USItype q0, q1; - USItype b, bm; + u32 d0, d1, n0, n1, n2; + u32 q0, q1; + u32 b, bm; nn.ll = n; dd.ll = d; @@ -185,7 +185,7 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp) } else { - USItype m1, m0; + u32 m1, m0; /* Normalize. */ b = SI_TYPE_SIZE - bm; @@ -224,16 +224,16 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp) return ww.ll; } -UDItype -__udivdi3 (UDItype n, UDItype d) +u64 +__udivdi3 (u64 n, u64 d) { - return __udivmoddi4 (n, d, (UDItype *) 0); + return __udivmoddi4 (n, d, (u64 *) 0); } -UDItype -__umoddi3 (UDItype u, UDItype v) +u64 +__umoddi3 (u64 u, u64 v) { - UDItype w; + u64 w; (void) __udivmoddi4 (u ,v, &w); -- cgit v0.10.2 From 3ade2fe0fd0238d68938b8f5f73ebd0561d2d2e5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Jun 2005 16:45:32 +0100 Subject: [PATCH] ARM: Lindent GCC helper functions Signed-off-by: Russell King diff --git a/arch/arm/lib/ashldi3.c b/arch/arm/lib/ashldi3.c index 02d2b62..b62875c 100644 --- a/arch/arm/lib/ashldi3.c +++ b/arch/arm/lib/ashldi3.c @@ -31,31 +31,26 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -s64 -__ashldi3 (s64 u, int b) +s64 __ashldi3(s64 u, int b) { - DIunion w; - int bm; - DIunion uu; - - if (b == 0) - return u; - - uu.ll = u; - - bm = (sizeof (s32) * BITS_PER_UNIT) - b; - if (bm <= 0) - { - w.s.low = 0; - w.s.high = (u32)uu.s.low << -bm; - } - else - { - u32 carries = (u32)uu.s.low >> bm; - w.s.low = (u32)uu.s.low << b; - w.s.high = ((u32)uu.s.high << b) | carries; - } - - return w.ll; + DIunion w; + int bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof(s32) * BITS_PER_UNIT) - b; + if (bm <= 0) { + w.s.low = 0; + w.s.high = (u32) uu.s.low << -bm; + } else { + u32 carries = (u32) uu.s.low >> bm; + w.s.low = (u32) uu.s.low << b; + w.s.high = ((u32) uu.s.high << b) | carries; + } + + return w.ll; } - diff --git a/arch/arm/lib/ashrdi3.c b/arch/arm/lib/ashrdi3.c index 89f6fb7..9a8600a 100644 --- a/arch/arm/lib/ashrdi3.c +++ b/arch/arm/lib/ashrdi3.c @@ -31,31 +31,27 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -s64 -__ashrdi3 (s64 u, int b) +s64 __ashrdi3(s64 u, int b) { - DIunion w; - int bm; - DIunion uu; - - if (b == 0) - return u; - - uu.ll = u; - - bm = (sizeof (s32) * BITS_PER_UNIT) - b; - if (bm <= 0) - { - /* w.s.high = 1..1 or 0..0 */ - w.s.high = uu.s.high >> (sizeof (s32) * BITS_PER_UNIT - 1); - w.s.low = uu.s.high >> -bm; - } - else - { - u32 carries = (u32)uu.s.high << bm; - w.s.high = uu.s.high >> b; - w.s.low = ((u32)uu.s.low >> b) | carries; - } - - return w.ll; + DIunion w; + int bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof(s32) * BITS_PER_UNIT) - b; + if (bm <= 0) { + /* w.s.high = 1..1 or 0..0 */ + w.s.high = uu.s.high >> (sizeof(s32) * BITS_PER_UNIT - 1); + w.s.low = uu.s.high >> -bm; + } else { + u32 carries = (u32) uu.s.high << bm; + w.s.high = uu.s.high >> b; + w.s.low = ((u32) uu.s.low >> b) | carries; + } + + return w.ll; } diff --git a/arch/arm/lib/gcclib.h b/arch/arm/lib/gcclib.h index 283f529..8b6dcc6 100644 --- a/arch/arm/lib/gcclib.h +++ b/arch/arm/lib/gcclib.h @@ -3,18 +3,20 @@ #include -#define BITS_PER_UNIT 8 -#define SI_TYPE_SIZE (sizeof(s32) * BITS_PER_UNIT) +#define BITS_PER_UNIT 8 +#define SI_TYPE_SIZE (sizeof(s32) * BITS_PER_UNIT) #ifdef __ARMEB__ - struct DIstruct {s32 high, low;}; +struct DIstruct { + s32 high, low; +}; #else - struct DIstruct {s32 low, high;}; +struct DIstruct { + s32 low, high; +}; #endif -typedef union -{ - struct DIstruct s; - s64 ll; +typedef union { + struct DIstruct s; + s64 ll; } DIunion; - diff --git a/arch/arm/lib/longlong.h b/arch/arm/lib/longlong.h index 3ef7695..90ae647 100644 --- a/arch/arm/lib/longlong.h +++ b/arch/arm/lib/longlong.h @@ -114,7 +114,7 @@ "r" ((u32) (b)));} #define UMUL_TIME 20 #define UDIV_TIME 100 -#endif /* __arm__ */ +#endif /* __arm__ */ #define __umulsidi3(u, v) \ ({DIunion __w; \ diff --git a/arch/arm/lib/lshrdi3.c b/arch/arm/lib/lshrdi3.c index 5c2385a..3681f49 100644 --- a/arch/arm/lib/lshrdi3.c +++ b/arch/arm/lib/lshrdi3.c @@ -31,31 +31,26 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -s64 -__lshrdi3 (s64 u, int b) +s64 __lshrdi3(s64 u, int b) { - DIunion w; - int bm; - DIunion uu; - - if (b == 0) - return u; - - uu.ll = u; - - bm = (sizeof (s32) * BITS_PER_UNIT) - b; - if (bm <= 0) - { - w.s.high = 0; - w.s.low = (u32)uu.s.high >> -bm; - } - else - { - u32 carries = (u32)uu.s.high << bm; - w.s.high = (u32)uu.s.high >> b; - w.s.low = ((u32)uu.s.low >> b) | carries; - } - - return w.ll; + DIunion w; + int bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof(s32) * BITS_PER_UNIT) - b; + if (bm <= 0) { + w.s.high = 0; + w.s.low = (u32) uu.s.high >> -bm; + } else { + u32 carries = (u32) uu.s.high << bm; + w.s.high = (u32) uu.s.high >> b; + w.s.low = ((u32) uu.s.low >> b) | carries; + } + + return w.ll; } - diff --git a/arch/arm/lib/muldi3.c b/arch/arm/lib/muldi3.c index 5b649fa..0a3b933 100644 --- a/arch/arm/lib/muldi3.c +++ b/arch/arm/lib/muldi3.c @@ -52,26 +52,21 @@ Boston, MA 02111-1307, USA. */ : "r" ((u32) (a)), \ "r" ((u32) (b)));} - #define __umulsidi3(u, v) \ ({DIunion __w; \ umul_ppmm (__w.s.high, __w.s.low, u, v); \ __w.ll; }) - -s64 -__muldi3 (s64 u, s64 v) +s64 __muldi3(s64 u, s64 v) { - DIunion w; - DIunion uu, vv; + DIunion w; + DIunion uu, vv; - uu.ll = u, - vv.ll = v; + uu.ll = u, vv.ll = v; - w.ll = __umulsidi3 (uu.s.low, vv.s.low); - w.s.high += ((u32) uu.s.low * (u32) vv.s.high - + (u32) uu.s.high * (u32) vv.s.low); + w.ll = __umulsidi3(uu.s.low, vv.s.low); + w.s.high += ((u32) uu.s.low * (u32) vv.s.high + + (u32) uu.s.high * (u32) vv.s.low); - return w.ll; + return w.ll; } - diff --git a/arch/arm/lib/ucmpdi2.c b/arch/arm/lib/ucmpdi2.c index 3eb438c..57f3f2d 100644 --- a/arch/arm/lib/ucmpdi2.c +++ b/arch/arm/lib/ucmpdi2.c @@ -31,21 +31,19 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" -int -__ucmpdi2 (s64 a, s64 b) +int __ucmpdi2(s64 a, s64 b) { - DIunion au, bu; - - au.ll = a, bu.ll = b; - - if ((u32) au.s.high < (u32) bu.s.high) - return 0; - else if ((u32) au.s.high > (u32) bu.s.high) - return 2; - if ((u32) au.s.low < (u32) bu.s.low) - return 0; - else if ((u32) au.s.low > (u32) bu.s.low) - return 2; - return 1; + DIunion au, bu; + + au.ll = a, bu.ll = b; + + if ((u32) au.s.high < (u32) bu.s.high) + return 0; + else if ((u32) au.s.high > (u32) bu.s.high) + return 2; + if ((u32) au.s.low < (u32) bu.s.low) + return 0; + else if ((u32) au.s.low > (u32) bu.s.low) + return 2; + return 1; } - diff --git a/arch/arm/lib/udivdi3.c b/arch/arm/lib/udivdi3.c index df1d5ef..e343be4 100644 --- a/arch/arm/lib/udivdi3.c +++ b/arch/arm/lib/udivdi3.c @@ -32,211 +32,191 @@ Boston, MA 02111-1307, USA. */ #include "gcclib.h" #include "longlong.h" -static const u8 __clz_tab[] = -{ - 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +static const u8 __clz_tab[] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, }; -u64 -__udivmoddi4 (u64 n, u64 d, u64 *rp) +u64 __udivmoddi4(u64 n, u64 d, u64 * rp) { - DIunion ww; - DIunion nn, dd; - DIunion rr; - u32 d0, d1, n0, n1, n2; - u32 q0, q1; - u32 b, bm; - - nn.ll = n; - dd.ll = d; - - d0 = dd.s.low; - d1 = dd.s.high; - n0 = nn.s.low; - n1 = nn.s.high; - - if (d1 == 0) - { - if (d0 > n1) - { - /* 0q = nn / 0D */ - - count_leading_zeros (bm, d0); - - if (bm != 0) - { - /* Normalize, i.e. make the most significant bit of the - denominator set. */ - - d0 = d0 << bm; - n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm)); - n0 = n0 << bm; - } - - udiv_qrnnd (q0, n0, n1, n0, d0); - q1 = 0; - - /* Remainder in n0 >> bm. */ - } - else - { - /* qq = NN / 0d */ - - if (d0 == 0) - d0 = 1 / d0; /* Divide intentionally by zero. */ - - count_leading_zeros (bm, d0); - - if (bm == 0) - { - /* From (n1 >= d0) /\ (the most significant bit of d0 is set), - conclude (the most significant bit of n1 is set) /\ (the - leading quotient digit q1 = 1). - - This special case is necessary, not an optimization. - (Shifts counts of SI_TYPE_SIZE are undefined.) */ - - n1 -= d0; - q1 = 1; - } - else - { - /* Normalize. */ - - b = SI_TYPE_SIZE - bm; - - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; - - udiv_qrnnd (q1, n1, n2, n1, d0); - } - - /* n1 != d0... */ - - udiv_qrnnd (q0, n0, n1, n0, d0); - - /* Remainder in n0 >> bm. */ - } - - if (rp != 0) - { - rr.s.low = n0 >> bm; - rr.s.high = 0; - *rp = rr.ll; - } - } - else - { - if (d1 > n1) - { - /* 00 = nn / DD */ - - q0 = 0; - q1 = 0; - - /* Remainder in n1n0. */ - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } - else - { - /* 0q = NN / dd */ - - count_leading_zeros (bm, d1); - if (bm == 0) - { - /* From (n1 >= d1) /\ (the most significant bit of d1 is set), - conclude (the most significant bit of n1 is set) /\ (the - quotient digit q0 = 0 or 1). - - This special case is necessary, not an optimization. */ - - /* The condition on the next line takes advantage of that - n1 >= d1 (true due to program flow). */ - if (n1 > d1 || n0 >= d0) - { - q0 = 1; - sub_ddmmss (n1, n0, n1, n0, d1, d0); - } - else - q0 = 0; - - q1 = 0; - - if (rp != 0) - { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } - else - { - u32 m1, m0; - /* Normalize. */ - - b = SI_TYPE_SIZE - bm; - - d1 = (d1 << bm) | (d0 >> b); - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; - - udiv_qrnnd (q0, n1, n2, n1, d1); - umul_ppmm (m1, m0, q0, d0); - - if (m1 > n1 || (m1 == n1 && m0 > n0)) - { - q0--; - sub_ddmmss (m1, m0, m1, m0, d1, d0); - } - - q1 = 0; - - /* Remainder in (n1n0 - m1m0) >> bm. */ - if (rp != 0) - { - sub_ddmmss (n1, n0, n1, n0, m1, m0); - rr.s.low = (n1 << b) | (n0 >> bm); - rr.s.high = n1 >> bm; - *rp = rr.ll; - } - } - } - } - - ww.s.low = q0; - ww.s.high = q1; - return ww.ll; + DIunion ww; + DIunion nn, dd; + DIunion rr; + u32 d0, d1, n0, n1, n2; + u32 q0, q1; + u32 b, bm; + + nn.ll = n; + dd.ll = d; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + + if (d1 == 0) { + if (d0 > n1) { + /* 0q = nn / 0D */ + + count_leading_zeros(bm, d0); + + if (bm != 0) { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd(q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } else { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros(bm, d0); + + if (bm == 0) { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). + + This special case is necessary, not an optimization. + (Shifts counts of SI_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } else { + /* Normalize. */ + + b = SI_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd(q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd(q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + if (rp != 0) { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } else { + if (d1 > n1) { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } else { + /* 0q = NN / dd */ + + count_leading_zeros(bm, d1); + if (bm == 0) { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) { + q0 = 1; + sub_ddmmss(n1, n0, n1, n0, d1, d0); + } else + q0 = 0; + + q1 = 0; + + if (rp != 0) { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } else { + u32 m1, m0; + /* Normalize. */ + + b = SI_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd(q0, n1, n2, n1, d1); + umul_ppmm(m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) { + q0--; + sub_ddmmss(m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) { + sub_ddmmss(n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + ww.s.low = q0; + ww.s.high = q1; + return ww.ll; } -u64 -__udivdi3 (u64 n, u64 d) +u64 __udivdi3(u64 n, u64 d) { - return __udivmoddi4 (n, d, (u64 *) 0); + return __udivmoddi4(n, d, (u64 *) 0); } -u64 -__umoddi3 (u64 u, u64 v) +u64 __umoddi3(u64 u, u64 v) { - u64 w; + u64 w; - (void) __udivmoddi4 (u ,v, &w); + (void)__udivmoddi4(u, v, &w); - return w; + return w; } - -- cgit v0.10.2 From 14eb75b6f83e3213d752dfe821df2fa57efbe519 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Jun 2005 16:56:08 +0100 Subject: [PATCH] ARM: Add missed include for dmabounce.c Signed-off-by: Russell King diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 39dd33f..9d63a01 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -30,6 +30,8 @@ #include #include +#include + #undef DEBUG #undef STATS -- cgit v0.10.2 From a507ef3ac68f0671fdd3f824885cd7f1ea1040b1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Jun 2005 16:57:17 +0100 Subject: [PATCH] ARM: Remove nmi_tick() from Integrator. Signed-off-by: Russell King diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index d302f04..bd1e5e3 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -227,7 +227,6 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * primary CPU */ if (hard_smp_processor_id() == 0) { - nmi_tick(); timer_tick(regs); #ifdef CONFIG_SMP smp_send_timer(); -- cgit v0.10.2 From 34b727c135ff651f153be5757056d25678b6d018 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Thu, 9 Jun 2005 22:36:00 -0700 Subject: [IA64] Drop spurious paren in entry.h The latest assembler catches this typo. (reported by Jim Wilson). Signed-off-by: David Mosberger-Tang Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/entry.h b/arch/ia64/kernel/entry.h index 6d4ecec..78eeb07 100644 --- a/arch/ia64/kernel/entry.h +++ b/arch/ia64/kernel/entry.h @@ -60,7 +60,7 @@ .spillsp @priunat,SW(AR_UNAT)+16+(off); \ .spillsp ar.rnat,SW(AR_RNAT)+16+(off); \ .spillsp ar.bspstore,SW(AR_BSPSTORE)+16+(off); \ - .spillsp pr,SW(PR)+16+(off)) + .spillsp pr,SW(PR)+16+(off) #define DO_SAVE_SWITCH_STACK \ movl r28=1f; \ -- cgit v0.10.2 From 09f0551d20ddf6d22c333adcc59f2b1148734273 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Jun 2005 18:44:37 +0100 Subject: [PATCH] ARM: Add iomap support for ARM Signed-off-by: Russell King diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 475950c..1a1773f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -67,10 +67,6 @@ config GENERIC_BUST_SPINLOCK config GENERIC_ISA_DMA bool -config GENERIC_IOMAP - bool - default y - config FIQ bool diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 00bb8fd..7110e54 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -170,3 +170,50 @@ void __iounmap(void __iomem *addr) vfree((void *) (PAGE_MASK & (unsigned long) addr)); } EXPORT_SYMBOL(__iounmap); + +#ifdef __io +void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + return __io(port); +} +EXPORT_SYMBOL(ioport_map); + +void ioport_unmap(void __iomem *addr) +{ +} +EXPORT_SYMBOL(ioport_unmap); +#endif + +#ifdef CONFIG_PCI +#include +#include + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len || !start) + return NULL; + if (maxlen && len > maxlen) + len = maxlen; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) { + if (flags & IORESOURCE_CACHEABLE) + return ioremap(start, len); + return ioremap_nocache(start, len); + } + return NULL; +} +EXPORT_SYMBOL(pci_iomap); + +void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +{ + if ((unsigned long)addr >= VMALLOC_START && + (unsigned long)addr < VMALLOC_END) + iounmap(addr); +} +EXPORT_SYMBOL(pci_iounmap); +#endif diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h index 658ffa3..08a4630 100644 --- a/include/asm-arm/io.h +++ b/include/asm-arm/io.h @@ -273,6 +273,33 @@ extern void __iounmap(void __iomem *addr); #endif /* + * io{read,write}{8,16,32} macros + */ +#define ioread8(p) ({ unsigned int __v = __raw_readb(p); __v; }) +#define ioread16(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(p)); __v; }) +#define ioread32(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(p)); __v; }) + +#define iowrite8(v,p) __raw_writeb(v, p) +#define iowrite16(v,p) __raw_writew(cpu_to_le16(v), p) +#define iowrite32(v,p) __raw_writel(cpu_to_le32(v), p) + +#define ioread8_rep(p,d,c) __raw_readsb(p,d,c) +#define ioread16_rep(p,d,c) __raw_readsw(p,d,c) +#define ioread32_rep(p,d,c) __raw_readsl(p,d,c) + +#define iowrite8_rep(p,s,c) __raw_writesb(p,s,c) +#define iowrite16_rep(p,s,c) __raw_writesw(p,s,c) +#define iowrite32_rep(p,s,c) __raw_writesl(p,s,c) + +extern void __iomem *ioport_map(unsigned long port, unsigned int nr); +extern void ioport_unmap(void __iomem *addr); + +struct pci_dev; + +extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen); +extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr); + +/* * can the hardware map this into one segment or not, given no other * constraints. */ -- cgit v0.10.2 From 038c5b602524b33447008492e932cdd0a1e806c9 Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Mon, 20 Jun 2005 18:51:05 +0100 Subject: [PATCH] ARM: 2686/2: AAEC-2000 Core support Patch from Bellido Nicolas Core support for AAEC-2000 based platforms. This is an updated version of the previous patch, and takes into account Russell's comments. AAED-2000 default configuration will follow as soon as some problems with the bootloader are sorted out... Signed-off-by: Nicolas Bellido Signed-off-by: Russell King diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1a1773f..efdb12d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -198,6 +198,11 @@ config ARCH_H720X help This enables support for systems based on the Hynix HMS720x +config ARCH_AAEC2000 + bool "Agilent AAEC-2000 based" + help + This enables support for systems based on the Agilent AAEC-2000 + endchoice source "arch/arm/mach-clps711x/Kconfig" @@ -230,6 +235,8 @@ source "arch/arm/mach-h720x/Kconfig" source "arch/arm/mach-versatile/Kconfig" +source "arch/arm/mach-aaec2000/Kconfig" + # Definitions to make life easier config ARCH_ACORN bool diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 2277e3d..8330495 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -97,6 +97,7 @@ textaddr-$(CONFIG_ARCH_FORTUNET) := 0xc0008000 machine-$(CONFIG_ARCH_VERSATILE) := versatile machine-$(CONFIG_ARCH_IMX) := imx machine-$(CONFIG_ARCH_H720X) := h720x + machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 ifeq ($(CONFIG_ARCH_EBSA110),y) # This is what happens if you forget the IOCS16 line. diff --git a/arch/arm/mach-aaec2000/Kconfig b/arch/arm/mach-aaec2000/Kconfig new file mode 100644 index 0000000..5e4bef9 --- /dev/null +++ b/arch/arm/mach-aaec2000/Kconfig @@ -0,0 +1,11 @@ +if ARCH_AAEC2000 + +menu "Agilent AAEC-2000 Implementations" + +config MACH_AAED2000 + bool "Agilent AAED-2000 Development Platform" + select CPU_ARM920T + +endmenu + +endif diff --git a/arch/arm/mach-aaec2000/Makefile b/arch/arm/mach-aaec2000/Makefile new file mode 100644 index 0000000..20ec838 --- /dev/null +++ b/arch/arm/mach-aaec2000/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the linux kernel. +# + +# Common support (must be linked before board specific support) +obj-y += core.o + +# Specific board support +obj-$(CONFIG_MACH_AAED2000) += aaed2000.o diff --git a/arch/arm/mach-aaec2000/aaed2000.c b/arch/arm/mach-aaec2000/aaed2000.c new file mode 100644 index 0000000..5417ca3 --- /dev/null +++ b/arch/arm/mach-aaec2000/aaed2000.c @@ -0,0 +1,48 @@ +/* + * linux/arch/arm/mach-aaec2000/aaed2000.c + * + * Support for the Agilent AAED-2000 Development Platform. + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "core.h" + +static void __init aaed2000_init_irq(void) +{ + aaec2000_init_irq(); +} + +static void __init aaed2000_map_io(void) +{ + aaec2000_map_io(); +} + +MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform") + MAINTAINER("Nicolas Bellido Y Ortega") + BOOT_MEM(0xf0000000, PIO_BASE, VIO_BASE) + MAPIO(aaed2000_map_io) + INITIRQ(aaed2000_init_irq) + .timer = &aaec2000_timer, +MACHINE_END diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c new file mode 100644 index 0000000..fc145b3 --- /dev/null +++ b/arch/arm/mach-aaec2000/core.c @@ -0,0 +1,157 @@ +/* + * linux/arch/arm/mach-aaec2000/core.c + * + * Code common to all AAEC-2000 machines + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* + * Common I/O mapping: + * + * Static virtual address mappings are as follow: + * + * 0xf8000000-0xf8001ffff: Devices connected to APB bus + * 0xf8002000-0xf8003ffff: Devices connected to AHB bus + * + * Below 0xe8000000 is reserved for vm allocation. + * + * The machine specific code must provide the extra mapping beside the + * default mapping provided here. + */ +static struct map_desc standard_io_desc[] __initdata = { + /* virtual physical length type */ + { VIO_APB_BASE, PIO_APB_BASE, IO_APB_LENGTH, MT_DEVICE }, + { VIO_AHB_BASE, PIO_AHB_BASE, IO_AHB_LENGTH, MT_DEVICE } +}; + +void __init aaec2000_map_io(void) +{ + iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); +} + +/* + * Interrupt handling routines + */ +static void aaec2000_int_ack(unsigned int irq) +{ + IRQ_INTSR = 1 << irq; +} + +static void aaec2000_int_mask(unsigned int irq) +{ + IRQ_INTENC |= (1 << irq); +} + +static void aaec2000_int_unmask(unsigned int irq) +{ + IRQ_INTENS |= (1 << irq); +} + +static struct irqchip aaec2000_irq_chip = { + .ack = aaec2000_int_ack, + .mask = aaec2000_int_mask, + .unmask = aaec2000_int_unmask, +}; + +void __init aaec2000_init_irq(void) +{ + unsigned int i; + + for (i = 0; i < NR_IRQS; i++) { + set_irq_handler(i, do_level_IRQ); + set_irq_chip(i, &aaec2000_irq_chip); + set_irq_flags(i, IRQF_VALID); + } + + /* Disable all interrupts */ + IRQ_INTENC = 0xffffffff; + + /* Clear any pending interrupts */ + IRQ_INTSR = IRQ_INTSR; +} + +/* + * Time keeping + */ +/* IRQs are disabled before entering here from do_gettimeofday() */ +static unsigned long aaec2000_gettimeoffset(void) +{ + unsigned long ticks_to_match, elapsed, usec; + + /* Get ticks before next timer match */ + ticks_to_match = TIMER1_LOAD - TIMER1_VAL; + + /* We need elapsed ticks since last match */ + elapsed = LATCH - ticks_to_match; + + /* Now, convert them to usec */ + usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH; + + return usec; +} + +/* We enter here with IRQs enabled */ +static irqreturn_t +aaec2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* TODO: Check timer accuracy */ + write_seqlock(&xtime_lock); + + timer_tick(regs); + TIMER1_CLEAR = 1; + + write_sequnlock(&xtime_lock); + + return IRQ_HANDLED; +} + +static struct irqaction aaec2000_timer_irq = { + .name = "AAEC-2000 Timer Tick", + .flags = SA_INTERRUPT, + .handler = aaec2000_timer_interrupt +}; + +static void __init aaec2000_timer_init(void) +{ + /* Disable timer 1 */ + TIMER1_CTRL = 0; + + /* We have somehow to generate a 100Hz clock. + * We then use the 508KHz timer in periodic mode. + */ + TIMER1_LOAD = LATCH; + TIMER1_CLEAR = 1; /* Clear interrupt */ + + setup_irq(INT_TMR1_OFL, &aaec2000_timer_irq); + + TIMER1_CTRL = TIMER_CTRL_ENABLE | + TIMER_CTRL_PERIODIC | + TIMER_CTRL_CLKSEL_508K; +} + +struct sys_timer aaec2000_timer = { + .init = aaec2000_timer_init, + .offset = aaec2000_gettimeoffset, +}; + diff --git a/arch/arm/mach-aaec2000/core.h b/arch/arm/mach-aaec2000/core.h new file mode 100644 index 0000000..91893d8 --- /dev/null +++ b/arch/arm/mach-aaec2000/core.h @@ -0,0 +1,16 @@ +/* + * linux/arch/arm/mach-aaec2000/core.h + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +struct sys_timer; + +extern struct sys_timer aaec2000_timer; +extern void __init aaec2000_map_io(void); +extern void __init aaec2000_init_irq(void); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 3fefb43..95606b4 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -62,7 +62,7 @@ config CPU_ARM720T # ARM920T config CPU_ARM920T bool "Support ARM920T processor" if !ARCH_S3C2410 - depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX + depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX || ARCH_AAEC2000 default y if ARCH_S3C2410 select CPU_32v4 select CPU_ABRT_EV4T diff --git a/include/asm-arm/arch-aaec2000/aaec2000.h b/include/asm-arm/arch-aaec2000/aaec2000.h new file mode 100644 index 0000000..0e9b7e1 --- /dev/null +++ b/include/asm-arm/arch-aaec2000/aaec2000.h @@ -0,0 +1,151 @@ +/* + * linux/include/asm-arm/arch-aaec2000/aaec2000.h + * + * AAEC-2000 registers definition + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_AAEC2000_H +#define __ASM_ARCH_AAEC2000_H + +#ifndef __ASM_ARCH_HARDWARE_H +#error You must include hardware.h not this file +#endif /* __ASM_ARCH_HARDWARE_H */ + +/* Interrupt controller */ +#define IRQ_BASE __REG(0x80000500) +#define IRQ_INTSR __REG(0x80000500) /* Int Status Register */ +#define IRQ_INTRSR __REG(0x80000504) /* Int Raw (unmasked) Status */ +#define IRQ_INTENS __REG(0x80000508) /* Int Enable Set */ +#define IRQ_INTENC __REG(0x8000050c) /* Int Enable Clear */ + +/* UART 1 */ +#define UART1_BASE __REG(0x80000600) +#define UART1_DR __REG(0x80000600) /* Data/FIFO Register */ +#define UART1_LCR __REG(0x80000604) /* Link Control Register */ +#define UART1_BRCR __REG(0x80000608) /* Baud Rate Control Register */ +#define UART1_CR __REG(0x8000060c) /* Control Register */ +#define UART1_SR __REG(0x80000610) /* Status Register */ +#define UART1_INT __REG(0x80000614) /* Interrupt Status Register */ +#define UART1_INTM __REG(0x80000618) /* Interrupt Mask Register */ +#define UART1_INTRES __REG(0x8000061c) /* Int Result (masked status) Register */ + +/* UART 2 */ +#define UART2_BASE __REG(0x80000700) +#define UART2_DR __REG(0x80000700) /* Data/FIFO Register */ +#define UART2_LCR __REG(0x80000704) /* Link Control Register */ +#define UART2_BRCR __REG(0x80000708) /* Baud Rate Control Register */ +#define UART2_CR __REG(0x8000070c) /* Control Register */ +#define UART2_SR __REG(0x80000710) /* Status Register */ +#define UART2_INT __REG(0x80000714) /* Interrupt Status Register */ +#define UART2_INTM __REG(0x80000718) /* Interrupt Mask Register */ +#define UART2_INTRES __REG(0x8000071c) /* Int Result (masked status) Register */ + +/* UART 3 */ +#define UART3_BASE __REG(0x80000800) +#define UART3_DR __REG(0x80000800) /* Data/FIFO Register */ +#define UART3_LCR __REG(0x80000804) /* Link Control Register */ +#define UART3_BRCR __REG(0x80000808) /* Baud Rate Control Register */ +#define UART3_CR __REG(0x8000080c) /* Control Register */ +#define UART3_SR __REG(0x80000810) /* Status Register */ +#define UART3_INT __REG(0x80000814) /* Interrupt Status Register */ +#define UART3_INTM __REG(0x80000818) /* Interrupt Mask Register */ +#define UART3_INTRES __REG(0x8000081c) /* Int Result (masked status) Register */ + +/* These are used in some places */ +#define _UART1_BASE __PREG(UART1_BASE) +#define _UART2_BASE __PREG(UART2_BASE) +#define _UART3_BASE __PREG(UART3_BASE) + +/* UART Registers Offsets */ +#define UART_DR 0x00 +#define UART_LCR 0x04 +#define UART_BRCR 0x08 +#define UART_CR 0x0c +#define UART_SR 0x10 +#define UART_INT 0x14 +#define UART_INTM 0x18 +#define UART_INTRES 0x1c + +/* UART_LCR Bitmask */ +#define UART_LCR_BRK (1 << 0) /* Send Break */ +#define UART_LCR_PEN (1 << 1) /* Parity Enable */ +#define UART_LCR_EP (1 << 2) /* Even/Odd Parity */ +#define UART_LCR_S2 (1 << 3) /* One/Two Stop bits */ +#define UART_LCR_FIFO (1 << 4) /* FIFO Enable */ +#define UART_LCR_WL5 (0 << 5) /* Word Length - 5 bits */ +#define UART_LCR_WL6 (1 << 5) /* Word Length - 6 bits */ +#define UART_LCR_WL7 (1 << 6) /* Word Length - 7 bits */ +#define UART_LCR_WL8 (1 << 7) /* Word Length - 8 bits */ + +/* UART_CR Bitmask */ +#define UART_CR_EN (1 << 0) /* UART Enable */ +#define UART_CR_SIR (1 << 1) /* IrDA SIR Enable */ +#define UART_CR_SIRLP (1 << 2) /* Low Power IrDA Enable */ +#define UART_CR_RXP (1 << 3) /* Receive Pin Polarity */ +#define UART_CR_TXP (1 << 4) /* Transmit Pin Polarity */ +#define UART_CR_MXP (1 << 5) /* Modem Pin Polarity */ +#define UART_CR_LOOP (1 << 6) /* Loopback Mode */ + +/* UART_SR Bitmask */ +#define UART_SR_CTS (1 << 0) /* Clear To Send Status */ +#define UART_SR_DSR (1 << 1) /* Data Set Ready Status */ +#define UART_SR_DCD (1 << 2) /* Data Carrier Detect Status */ +#define UART_SR_TxBSY (1 << 3) /* Transmitter Busy Status */ +#define UART_SR_RxFE (1 << 4) /* Receive FIFO Empty Status */ +#define UART_SR_TxFF (1 << 5) /* Transmit FIFO Full Status */ +#define UART_SR_RxFF (1 << 6) /* Receive FIFO Full Status */ +#define UART_SR_TxFE (1 << 7) /* Transmit FIFO Empty Status */ + +/* UART_INT Bitmask */ +#define UART_INT_RIS (1 << 0) /* Rx Interrupt */ +#define UART_INT_TIS (1 << 1) /* Tx Interrupt */ +#define UART_INT_MIS (1 << 2) /* Modem Interrupt */ +#define UART_INT_RTIS (1 << 3) /* Receive Timeout Interrupt */ + +/* Timer 1 */ +#define TIMER1_BASE __REG(0x80000c00) +#define TIMER1_LOAD __REG(0x80000c00) /* Timer 1 Load Register */ +#define TIMER1_VAL __REG(0x80000c04) /* Timer 1 Value Register */ +#define TIMER1_CTRL __REG(0x80000c08) /* Timer 1 Control Register */ +#define TIMER1_CLEAR __REG(0x80000c0c) /* Timer 1 Clear Register */ + +/* Timer 2 */ +#define TIMER2_BASE __REG(0x80000d00) +#define TIMER2_LOAD __REG(0x80000d00) /* Timer 2 Load Register */ +#define TIMER2_VAL __REG(0x80000d04) /* Timer 2 Value Register */ +#define TIMER2_CTRL __REG(0x80000d08) /* Timer 2 Control Register */ +#define TIMER2_CLEAR __REG(0x80000d0c) /* Timer 2 Clear Register */ + +/* Timer 3 */ +#define TIMER3_BASE __REG(0x80000e00) +#define TIMER3_LOAD __REG(0x80000e00) /* Timer 3 Load Register */ +#define TIMER3_VAL __REG(0x80000e04) /* Timer 3 Value Register */ +#define TIMER3_CTRL __REG(0x80000e08) /* Timer 3 Control Register */ +#define TIMER3_CLEAR __REG(0x80000e0c) /* Timer 3 Clear Register */ + +/* Timer Control register bits */ +#define TIMER_CTRL_ENABLE (1 << 7) /* Enable (Start° Timer */ +#define TIMER_CTRL_PERIODIC (1 << 6) /* Periodic Running Mode */ +#define TIMER_CTRL_FREE_RUNNING (0 << 6) /* Normal Running Mode */ +#define TIMER_CTRL_CLKSEL_508K (1 << 3) /* 508KHz Clock select (Timer 1, 2) */ +#define TIMER_CTRL_CLKSEL_2K (0 << 3) /* 2KHz Clock Select (Timer 1, 2)*/ + +/* Power and State Control */ +#define POWER_BASE __REG(0x80000400) +#define POWER_PWRSR __REG(0x80000400) /* Power Status Register */ +#define POWER_PWRCNT __REG(0x80000404) /* Power/Clock control */ +#define POWER_HALT __REG(0x80000408) /* Power Idle Mode */ +#define POWER_STDBY __REG(0x8000040c) /* Power Standby Mode */ +#define POWER_BLEOI __REG(0x80000410) /* Battery Low End of Interrupt */ +#define POWER_MCEOI __REG(0x80000414) /* Media Changed EoI */ +#define POWER_TEOI __REG(0x80000418) /* Tick EoI */ +#define POWER_STFCLR __REG(0x8000041c) /* NbFlg, RSTFlg, PFFlg, CLDFlg Clear */ +#define POWER_CLKSET __REG(0x80000420) /* Clock Speed Control */ + +#endif /* __ARM_ARCH_AAEC2000_H */ diff --git a/include/asm-arm/arch-aaec2000/debug-macro.S b/include/asm-arm/arch-aaec2000/debug-macro.S new file mode 100644 index 0000000..e4f1fa5 --- /dev/null +++ b/include/asm-arm/arch-aaec2000/debug-macro.S @@ -0,0 +1,36 @@ +/* linux/include/asm-arm/arch-aaec2000/debug-macro.S + * + * Debugging macro include header + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x80000000 @ physical + movne \rx, #io_p2v(0x80000000) @ virtual + orr \rx, \rx, #0x00000800 + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0] + .endm + + .macro busyuart,rd,rx +1002: ldr \rd, [\rx, #0x10] + tst \rd, #(1 << 7) + beq 1002b + .endm + + .macro waituart,rd,rx +#if 0 +1001: ldr \rd, [\rx, #0x10] + tst \rd, #(1 << 5) + beq 1001b +#endif + .endm diff --git a/include/asm-arm/arch-aaec2000/dma.h b/include/asm-arm/arch-aaec2000/dma.h new file mode 100644 index 0000000..28c890b --- /dev/null +++ b/include/asm-arm/arch-aaec2000/dma.h @@ -0,0 +1,17 @@ +/* + * linux/include/asm-arm/arch-aaec2000/dma.h + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_ADDRESS 0xffffffff +#define MAX_DMA_CHANNELS 0 + +#endif diff --git a/include/asm-arm/arch-aaec2000/entry-macro.S b/include/asm-arm/arch-aaec2000/entry-macro.S new file mode 100644 index 0000000..df31313 --- /dev/null +++ b/include/asm-arm/arch-aaec2000/entry-macro.S @@ -0,0 +1,33 @@ +/* + * linux/include/asm-arm/arch-aaec2000/entry-macro.S + * + * Low-level IRQ helper for aaec-2000 based platforms + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + mov r4, #0xf8000000 + add r4, r4, #0x00000500 + mov \base, r4 + ldr \irqstat, [\base, #0] + cmp \irqstat, #0 + bne 1001f + ldr \irqnr, =NR_IRQS+1 + b 1003f +1001: mov \irqnr, #0 +1002: ands \tmp, \irqstat, #1 + mov \irqstat, \irqstat, LSR #1 + add \irqnr, \irqnr, #1 + beq 1002b + sub \irqnr, \irqnr, #1 +1003: + .endm diff --git a/include/asm-arm/arch-aaec2000/hardware.h b/include/asm-arm/arch-aaec2000/hardware.h new file mode 100644 index 0000000..4c37219 --- /dev/null +++ b/include/asm-arm/arch-aaec2000/hardware.h @@ -0,0 +1,49 @@ +/* + * linux/include/asm-arm/arch-aaec2000/hardware.h + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include + +/* The kernel is loaded at physical address 0xf8000000. + * We map the IO space a bit after + */ +#define PIO_APB_BASE 0x80000000 +#define VIO_APB_BASE 0xf8000000 +#define IO_APB_LENGTH 0x2000 +#define PIO_AHB_BASE 0x80002000 +#define VIO_AHB_BASE 0xf8002000 +#define IO_AHB_LENGTH 0x2000 + +#define VIO_BASE VIO_APB_BASE +#define PIO_BASE PIO_APB_BASE + +#define io_p2v(x) ( (x) - PIO_BASE + VIO_BASE ) +#define io_v2p(x) ( (x) + PIO_BASE - VIO_BASE ) + +#ifndef __ASSEMBLY__ + +#include + +/* FIXME: Is it needed to optimize this a la pxa ?? */ +#define __REG(x) (*((volatile u32 *)io_p2v(x))) +#define __PREG(x) (io_v2p((u32)&(x))) + +#else /* __ASSEMBLY__ */ + +#define __REG(x) io_p2v(x) +#define __PREG(x) io_v2p(x) + +#endif + +#include "aaec2000.h" + +#endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-aaec2000/io.h b/include/asm-arm/arch-aaec2000/io.h new file mode 100644 index 0000000..c58a8d1 --- /dev/null +++ b/include/asm-arm/arch-aaec2000/io.h @@ -0,0 +1,19 @@ +/* + * linux/include/asm-arm/arch-aaec2000/io.h + * + * Copied from asm/arch/sa1100/io.h + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * We don't actually have real ISA nor PCI buses, but there is so many + * drivers out there that might just work if we fake them... + */ +#define __io(a) ((void __iomem *)(a)) +#define __mem_pci(a) (a) +#define __mem_isa(a) (a) + +#endif diff --git a/include/asm-arm/arch-aaec2000/irqs.h b/include/asm-arm/arch-aaec2000/irqs.h new file mode 100644 index 0000000..de25222 --- /dev/null +++ b/include/asm-arm/arch-aaec2000/irqs.h @@ -0,0 +1,46 @@ +/* + * linux/include/asm-arm/arch-aaec2000/irqs.h + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_IRQS_H +#define __ASM_ARCH_IRQS_H + + +#define INT_GPIOF0_FIQ 0 /* External GPIO Port F O Fast Interrupt Input */ +#define INT_BL_FIQ 1 /* Battery Low Fast Interrupt */ +#define INT_WE_FIQ 2 /* Watchdog Expired Fast Interrupt */ +#define INT_MV_FIQ 3 /* Media Changed Interrupt */ +#define INT_SC 4 /* Sound Codec Interrupt */ +#define INT_GPIO1 5 /* GPIO Port F Configurable Int 1 */ +#define INT_GPIO2 6 /* GPIO Port F Configurable Int 2 */ +#define INT_GPIO3 7 /* GPIO Port F Configurable Int 3 */ +#define INT_TMR1_OFL 8 /* Timer 1 Overflow Interrupt */ +#define INT_TMR2_OFL 9 /* Timer 2 Overflow Interrupt */ +#define INT_RTC_CM 10 /* RTC Compare Match Interrupt */ +#define INT_TICK 11 /* 64Hz Tick Interrupt */ +#define INT_UART1 12 /* UART1 Interrupt */ +#define INT_UART2 13 /* UART2 & Modem State Changed Interrupt */ +#define INT_LCD 14 /* LCD Interrupt */ +#define INT_SSI 15 /* SSI End of Transfer Interrupt */ +#define INT_UART3 16 /* UART3 Interrupt */ +#define INT_SCI 17 /* SCI Interrupt */ +#define INT_AAC 18 /* Advanced Audio Codec Interrupt */ +#define INT_MMC 19 /* MMC Interrupt */ +#define INT_USB 20 /* USB Interrupt */ +#define INT_DMA 21 /* DMA Interrupt */ +#define INT_TMR3_UOFL 22 /* Timer 3 Underflow Interrupt */ +#define INT_GPIO4 23 /* GPIO Port F Configurable Int 4 */ +#define INT_GPIO5 24 /* GPIO Port F Configurable Int 4 */ +#define INT_GPIO6 25 /* GPIO Port F Configurable Int 4 */ +#define INT_GPIO7 26 /* GPIO Port F Configurable Int 4 */ +#define INT_BMI 27 /* BMI Interrupt */ + +#define NR_IRQS (INT_BMI + 1) + +#endif /* __ASM_ARCH_IRQS_H */ diff --git a/include/asm-arm/arch-aaec2000/memory.h b/include/asm-arm/arch-aaec2000/memory.h new file mode 100644 index 0000000..681b6a6 --- /dev/null +++ b/include/asm-arm/arch-aaec2000/memory.h @@ -0,0 +1,73 @@ +/* + * linux/include/asm-arm/arch-aaec2000/memory.h + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#include + +#define PHYS_OFFSET (0xf0000000UL) + +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt(x) __phys_to_virt(x) + +#ifdef CONFIG_DISCONTIGMEM + +/* + * The nodes are the followings: + * + * node 0: 0xf000.0000 - 0xf3ff.ffff + * node 1: 0xf400.0000 - 0xf7ff.ffff + * node 2: 0xf800.0000 - 0xfbff.ffff + * node 3: 0xfc00.0000 - 0xffff.ffff + */ + +/* + * Given a kernel address, find the home node of the underlying memory. + */ +#define KVADDR_TO_NID(addr) \ + (((unsigned long)(addr) - PAGE_OFFSET) >> NODE_MAX_MEM_SHIFT) + +/* + * Given a page frame number, convert it to a node id. + */ +#define PFN_TO_NID(pfn) \ + (((pfn) - PHYS_PFN_OFFSET) >> (NODE_MAX_MEM_SHIFT - PAGE_SHIFT)) + +/* + * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory + * and return the mem_map of that node. + */ +#define ADDR_TO_MAPBASE(kaddr) NODE_MEM_MAP(KVADDR_TO_NID(kaddr)) + +/* + * Given a page frame number, find the owning node of the memory + * and return the mem_map of that node. + */ +#define PFN_TO_MAPBASE(pfn) NODE_MEM_MAP(PFN_TO_NID(pfn)) + +/* + * Given a kaddr, LOCAL_MEM_MAP finds the owning node of the memory + * and returns the index corresponding to the appropriate page in the + * node's mem_map. + */ +#define LOCAL_MAP_NR(addr) \ + (((unsigned long)(addr) & (NODE_MAX_MEM_SIZE - 1)) >> PAGE_SHIFT) + +#define NODE_MAX_MEM_SHIFT 26 +#define NODE_MAX_MEM_SIZE (1 << NODE_MAX_MEM_SHIFT) + +#else + +#define PFN_TO_NID(addr) (0) + +#endif /* CONFIG_DISCONTIGMEM */ + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/include/asm-arm/arch-aaec2000/param.h b/include/asm-arm/arch-aaec2000/param.h new file mode 100644 index 0000000..139936c --- /dev/null +++ b/include/asm-arm/arch-aaec2000/param.h @@ -0,0 +1,15 @@ +/* + * linux/include/asm-arm/arch-aaec2000/param.h + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_PARAM_H +#define __ASM_ARCH_PARAM_H + +#endif /* __ASM_ARCH_PARAM_H */ + diff --git a/include/asm-arm/arch-aaec2000/system.h b/include/asm-arm/arch-aaec2000/system.h new file mode 100644 index 0000000..08de97b --- /dev/null +++ b/include/asm-arm/arch-aaec2000/system.h @@ -0,0 +1,24 @@ +/* + * linux/include/asm-arm/arch-aaed2000/system.h + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +static inline void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + cpu_reset(0); +} + +#endif /* __ASM_ARCH_SYSTEM_H */ diff --git a/include/asm-arm/arch-aaec2000/timex.h b/include/asm-arm/arch-aaec2000/timex.h new file mode 100644 index 0000000..f5708b3 --- /dev/null +++ b/include/asm-arm/arch-aaec2000/timex.h @@ -0,0 +1,18 @@ +/* + * linux/include/asm-arm/arch-aaec2000/timex.h + * + * AAEC-2000 Architecture timex specification + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_TIMEX_H +#define __ASM_ARCH_TIMEX_H + +#define CLOCK_TICK_RATE 508000 + +#endif /* __ASM_ARCH_TIMEX_H */ diff --git a/include/asm-arm/arch-aaec2000/uncompress.h b/include/asm-arm/arch-aaec2000/uncompress.h new file mode 100644 index 0000000..fff0c94 --- /dev/null +++ b/include/asm-arm/arch-aaec2000/uncompress.h @@ -0,0 +1,47 @@ +/* + * linux/include/asm-arm/arch-aaec2000/uncompress.h + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_UNCOMPRESS_H +#define __ASM_ARCH_UNCOMPRESS_H + +#include "hardware.h" + +#define UART(x) (*(volatile unsigned long *)(serial_port + (x))) + +static void putstr( const char *s ) +{ + unsigned long serial_port; + do { + serial_port = _UART3_BASE; + if (UART(UART_CR) & UART_CR_EN) break; + serial_port = _UART1_BASE; + if (UART(UART_CR) & UART_CR_EN) break; + serial_port = _UART2_BASE; + if (UART(UART_CR) & UART_CR_EN) break; + return; + } while (0); + + for (; *s; s++) { + /* wait for space in the UART's transmitter */ + while ((UART(UART_SR) & UART_SR_TxFF)); + /* send the character out. */ + UART(UART_DR) = *s; + /* if a LF, also do CR... */ + if (*s == 10) { + while ((UART(UART_SR) & UART_SR_TxFF)); + UART(UART_DR) = 13; + } + } +} + +#define arch_decomp_setup() +#define arch_decomp_wdog() + +#endif /* __ASM_ARCH_UNCOMPRESS_H */ diff --git a/include/asm-arm/arch-aaec2000/vmalloc.h b/include/asm-arm/arch-aaec2000/vmalloc.h new file mode 100644 index 0000000..ecb991e --- /dev/null +++ b/include/asm-arm/arch-aaec2000/vmalloc.h @@ -0,0 +1,16 @@ +/* + * linux/include/asm-arm/arch-aaec2000/vmalloc.h + * + * Copyright (c) 2005 Nicolas Bellido Y Ortega + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_VMALLOC_H +#define __ASM_ARCH_VMALLOC_H + +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) + +#endif /* __ASM_ARCH_VMALLOC_H */ -- cgit v0.10.2 From c0da085ad2e6b1419b8a7439538f7f15eb5c4777 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 20 Jun 2005 18:51:06 +0100 Subject: [PATCH] ARM: 2693/1: Add PCI support for Versatile/PB Patch from Catalin Marinas This patch adds PCI support for the Versatile PB926 platform. Signed-off-by: Colin King Signed-off-by: Catalin Marinas Signed-off-by: Russell King diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index efdb12d..ee8a9ad 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -280,7 +280,7 @@ config ISA_DMA_API default y config PCI - bool "PCI support" if ARCH_INTEGRATOR_AP + bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside diff --git a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile index 5d60883..ba81e70 100644 --- a/arch/arm/mach-versatile/Makefile +++ b/arch/arm/mach-versatile/Makefile @@ -5,3 +5,4 @@ obj-y := core.o clock.o obj-$(CONFIG_ARCH_VERSATILE_PB) += versatile_pb.o obj-$(CONFIG_MACH_VERSATILE_AB) += versatile_ab.o +obj-$(CONFIG_PCI) += pci.o diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 302c2a7..6a7cbea 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -196,11 +196,15 @@ static struct map_desc versatile_io_desc[] __initdata = { #ifdef CONFIG_DEBUG_LL { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE }, #endif -#ifdef FIXME - { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, - { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, - { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_512K, MT_DEVICE }, - { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE }, +#ifdef CONFIG_PCI + { IO_ADDRESS(VERSATILE_PCI_CORE_BASE), VERSATILE_PCI_CORE_BASE, SZ_4K, MT_DEVICE }, + { VERSATILE_PCI_VIRT_BASE, VERSATILE_PCI_BASE, VERSATILE_PCI_BASE_SIZE, MT_DEVICE }, + { VERSATILE_PCI_CFG_VIRT_BASE, VERSATILE_PCI_CFG_BASE, VERSATILE_PCI_CFG_BASE_SIZE, MT_DEVICE }, +#if 0 + { VERSATILE_PCI_VIRT_MEM_BASE0, VERSATILE_PCI_MEM_BASE0, SZ_16M, MT_DEVICE }, + { VERSATILE_PCI_VIRT_MEM_BASE1, VERSATILE_PCI_MEM_BASE1, SZ_16M, MT_DEVICE }, + { VERSATILE_PCI_VIRT_MEM_BASE2, VERSATILE_PCI_MEM_BASE2, SZ_16M, MT_DEVICE }, +#endif #endif }; diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c new file mode 100644 index 0000000..d1565e8 --- /dev/null +++ b/arch/arm/mach-versatile/pci.c @@ -0,0 +1,360 @@ +/* + * linux/arch/arm/mach-versatile/pci.c + * + * (C) Copyright Koninklijke Philips Electronics NV 2004. All rights reserved. + * You can redistribute and/or modify this software under the terms of version 2 + * of the GNU General Public License as published by the Free Software Foundation. + * THIS SOFTWARE IS PROVIDED "AS IS" 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. + * Koninklijke Philips Electronics nor its subsidiaries is obligated to provide any support for this software. + * + * ARM Versatile PCI driver. + * + * 14/04/2005 Initial version, colin.king@philips.com + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * these spaces are mapped using the following base registers: + * + * Usage Local Bus Memory Base/Map registers used + * + * Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0, non prefetch + * Mem 60000000 - 6FFFFFFF LB_BASE1/LB_MAP1, prefetch + * IO 44000000 - 4FFFFFFF LB_BASE2/LB_MAP2, IO + * Cfg 42000000 - 42FFFFFF PCI config + * + */ +#define SYS_PCICTL IO_ADDRESS(VERSATILE_SYS_PCICTL) +#define PCI_IMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0) +#define PCI_IMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4) +#define PCI_IMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8) +#define PCI_SMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10) +#define PCI_SMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14) +#define PCI_SMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18) +#define PCI_SELFID IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc) + +#define DEVICE_ID_OFFSET 0x00 +#define CSR_OFFSET 0x04 +#define CLASS_ID_OFFSET 0x08 + +#define VP_PCI_DEVICE_ID 0x030010ee +#define VP_PCI_CLASS_ID 0x0b400000 + +static unsigned long pci_slot_ignore = 0; + +static int __init versatile_pci_slot_ignore(char *str) +{ + int retval; + int slot; + + while ((retval = get_option(&str,&slot))) { + if ((slot < 0) || (slot > 31)) { + printk("Illegal slot value: %d\n",slot); + } else { + pci_slot_ignore |= (1 << slot); + } + } + return 1; +} + +__setup("pci_slot_ignore=", versatile_pci_slot_ignore); + + +static unsigned long __pci_addr(struct pci_bus *bus, + unsigned int devfn, int offset) +{ + unsigned int busnr = bus->number; + + /* + * Trap out illegal values + */ + if (offset > 255) + BUG(); + if (busnr > 255) + BUG(); + if (devfn > 255) + BUG(); + + return (VERSATILE_PCI_CFG_VIRT_BASE | (busnr << 16) | + (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | offset); +} + +static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *val) +{ + unsigned long addr = __pci_addr(bus, devfn, where); + u32 v; + int slot = PCI_SLOT(devfn); + + if (pci_slot_ignore & (1 << slot)) { + /* Ignore this slot */ + switch (size) { + case 1: + v = 0xff; + break; + case 2: + v = 0xffff; + break; + default: + v = 0xffffffff; + } + } else { + switch (size) { + case 1: + addr &= ~3; + v = __raw_readb(addr); + break; + + case 2: + v = __raw_readl(addr & ~3); + if (addr & 2) v >>= 16; + v &= 0xffff; + break; + + default: + addr &= ~3; + v = __raw_readl(addr); + break; + } + } + + *val = v; + return PCIBIOS_SUCCESSFUL; +} + +static int versatile_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) +{ + unsigned long addr = __pci_addr(bus, devfn, where); + int slot = PCI_SLOT(devfn); + + if (pci_slot_ignore & (1 << slot)) { + return PCIBIOS_SUCCESSFUL; + } + + switch (size) { + case 1: + __raw_writeb((u8)val, addr); + break; + + case 2: + __raw_writew((u16)val, addr); + break; + + case 4: + __raw_writel(val, addr); + break; + } + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pci_versatile_ops = { + .read = versatile_read_config, + .write = versatile_write_config, +}; + +static struct resource io_mem = { + .name = "PCI I/O space", + .start = VERSATILE_PCI_MEM_BASE0, + .end = VERSATILE_PCI_MEM_BASE0+VERSATILE_PCI_MEM_BASE0_SIZE-1, + .flags = IORESOURCE_IO, +}; + +static struct resource non_mem = { + .name = "PCI non-prefetchable", + .start = VERSATILE_PCI_MEM_BASE1, + .end = VERSATILE_PCI_MEM_BASE1+VERSATILE_PCI_MEM_BASE1_SIZE-1, + .flags = IORESOURCE_MEM, +}; + +static struct resource pre_mem = { + .name = "PCI prefetchable", + .start = VERSATILE_PCI_MEM_BASE2, + .end = VERSATILE_PCI_MEM_BASE2+VERSATILE_PCI_MEM_BASE2_SIZE-1, + .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH, +}; + +static int __init pci_versatile_setup_resources(struct resource **resource) +{ + int ret = 0; + + ret = request_resource(&iomem_resource, &io_mem); + if (ret) { + printk(KERN_ERR "PCI: unable to allocate I/O " + "memory region (%d)\n", ret); + goto out; + } + ret = request_resource(&iomem_resource, &non_mem); + if (ret) { + printk(KERN_ERR "PCI: unable to allocate non-prefetchable " + "memory region (%d)\n", ret); + goto release_io_mem; + } + ret = request_resource(&iomem_resource, &pre_mem); + if (ret) { + printk(KERN_ERR "PCI: unable to allocate prefetchable " + "memory region (%d)\n", ret); + goto release_non_mem; + } + + /* + * bus->resource[0] is the IO resource for this bus + * bus->resource[1] is the mem resource for this bus + * bus->resource[2] is the prefetch mem resource for this bus + */ + resource[0] = &io_mem; + resource[1] = &non_mem; + resource[2] = &pre_mem; + + goto out; + + release_non_mem: + release_resource(&non_mem); + release_io_mem: + release_resource(&io_mem); + out: + return ret; +} + +int __init pci_versatile_setup(int nr, struct pci_sys_data *sys) +{ + int ret = 0; + int i; + int myslot = -1; + unsigned long val; + + if (nr == 0) { + sys->mem_offset = 0; + ret = pci_versatile_setup_resources(sys->resource); + if (ret < 0) { + printk("pci_versatile_setup: resources... oops?\n"); + goto out; + } + } else { + printk("pci_versatile_setup: resources... nr == 0??\n"); + goto out; + } + + __raw_writel(VERSATILE_PCI_MEM_BASE0 >> 28,PCI_IMAP0); + __raw_writel(VERSATILE_PCI_MEM_BASE1 >> 28,PCI_IMAP1); + __raw_writel(VERSATILE_PCI_MEM_BASE2 >> 28,PCI_IMAP2); + + __raw_writel(1, SYS_PCICTL); + + val = __raw_readl(SYS_PCICTL); + if (!(val & 1)) { + printk("Not plugged into PCI backplane!\n"); + ret = -EIO; + goto out; + } + + /* + * We need to discover the PCI core first to configure itself + * before the main PCI probing is performed + */ + for (i=0; i<32; i++) { + if ((__raw_readl(VERSATILE_PCI_VIRT_BASE+(i<<11)+DEVICE_ID_OFFSET) == VP_PCI_DEVICE_ID) && + (__raw_readl(VERSATILE_PCI_VIRT_BASE+(i<<11)+CLASS_ID_OFFSET) == VP_PCI_CLASS_ID)) { + myslot = i; + + __raw_writel(myslot, PCI_SELFID); + val = __raw_readl(VERSATILE_PCI_CFG_VIRT_BASE+(myslot<<11)+CSR_OFFSET); + val |= (1<<2); + __raw_writel(val, VERSATILE_PCI_CFG_VIRT_BASE+(myslot<<11)+CSR_OFFSET); + break; + } + } + + if (myslot == -1) { + printk("Cannot find PCI core!\n"); + ret = -EIO; + } else { + printk("PCI core found (slot %d)\n",myslot); + /* Do not to map Versatile FPGA PCI device + into memory space as we are short of + mappable memory */ + pci_slot_ignore |= (1 << myslot); + ret = 1; + } + + out: + return ret; +} + + +struct pci_bus *pci_versatile_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(sys->busnr, &pci_versatile_ops, sys); +} + +/* + * V3_LB_BASE? - local bus address + * V3_LB_MAP? - pci bus address + */ +void __init pci_versatile_preinit(void) +{ +} + +void __init pci_versatile_postinit(void) +{ +} + + +/* + * map the specified device/slot/pin to an IRQ. Different backplanes may need to modify this. + */ +static int __init versatile_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq; + int devslot = PCI_SLOT(dev->devfn); + + /* slot, pin, irq + 24 1 27 + 25 1 28 untested + 26 1 29 + 27 1 30 untested + */ + + irq = 27 + ((slot + pin + 2) % 3); /* Fudged */ + + printk("map irq: slot %d, pin %d, devslot %d, irq: %d\n",slot,pin,devslot,irq); + + return irq; +} + +static struct hw_pci versatile_pci __initdata = { + .swizzle = NULL, + .map_irq = versatile_map_irq, + .nr_controllers = 1, + .setup = pci_versatile_setup, + .scan = pci_versatile_scan_bus, + .preinit = pci_versatile_preinit, + .postinit = pci_versatile_postinit, +}; + +static int __init versatile_pci_init(void) +{ + pci_common_init(&versatile_pci); + return 0; +} + +subsys_initcall(versatile_pci_init); diff --git a/include/asm-arm/arch-versatile/hardware.h b/include/asm-arm/arch-versatile/hardware.h index d5fb4a2..41c1bee 100644 --- a/include/asm-arm/arch-versatile/hardware.h +++ b/include/asm-arm/arch-versatile/hardware.h @@ -25,19 +25,26 @@ #include #include -// FIXME = PCI settings need to be fixed!!!!! - /* - * Similar to above, but for PCI addresses (memory, IO, Config and the - * V3 chip itself). WARNING: this has to mirror definitions in platform.h + * PCI space virtual addresses */ -#define PCI_MEMORY_VADDR 0xe8000000 -#define PCI_CONFIG_VADDR 0xec000000 -#define PCI_V3_VADDR 0xed000000 -#define PCI_IO_VADDR 0xee000000 +#define VERSATILE_PCI_VIRT_BASE 0xe8000000 +#define VERSATILE_PCI_CFG_VIRT_BASE 0xe9000000 + +#if 0 +#define VERSATILE_PCI_VIRT_MEM_BASE0 0xf4000000 +#define VERSATILE_PCI_VIRT_MEM_BASE1 0xf5000000 +#define VERSATILE_PCI_VIRT_MEM_BASE2 0xf6000000 + +#define PCIO_BASE VERSATILE_PCI_VIRT_MEM_BASE0 +#define PCIMEM_BASE VERSATILE_PCI_VIRT_MEM_BASE1 +#endif + +/* CIK guesswork */ +#define PCIBIOS_MIN_IO 0x44000000 +#define PCIBIOS_MIN_MEM 0x50000000 -#define PCIO_BASE PCI_IO_VADDR -#define PCIMEM_BASE PCI_MEMORY_VADDR +#define pcibios_assign_all_busses() 1 /* macro to get at IO space when running virtually */ #define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) diff --git a/include/asm-arm/arch-versatile/io.h b/include/asm-arm/arch-versatile/io.h index dbb7158..9f895bf 100644 --- a/include/asm-arm/arch-versatile/io.h +++ b/include/asm-arm/arch-versatile/io.h @@ -20,7 +20,7 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H -#define IO_SPACE_LIMIT 0xffff +#define IO_SPACE_LIMIT 0xffffffff #define __io(a) ((void __iomem *)(a)) #define __mem_pci(a) (a) diff --git a/include/asm-arm/arch-versatile/platform.h b/include/asm-arm/arch-versatile/platform.h index a71093e..cbdd9fb 100644 --- a/include/asm-arm/arch-versatile/platform.h +++ b/include/asm-arm/arch-versatile/platform.h @@ -76,7 +76,7 @@ #define VERSATILE_SYS_NVFLAGSSET_OFFSET 0x38 #define VERSATILE_SYS_NVFLAGSCLR_OFFSET 0x3C #define VERSATILE_SYS_RESETCTL_OFFSET 0x40 -#define VERSATILE_SYS_PICCTL_OFFSET 0x44 +#define VERSATILE_SYS_PCICTL_OFFSET 0x44 #define VERSATILE_SYS_MCI_OFFSET 0x48 #define VERSATILE_SYS_FLASH_OFFSET 0x4C #define VERSATILE_SYS_CLCD_OFFSET 0x50 @@ -114,7 +114,7 @@ #define VERSATILE_SYS_NVFLAGSSET (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGSSET_OFFSET) #define VERSATILE_SYS_NVFLAGSCLR (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGSCLR_OFFSET) #define VERSATILE_SYS_RESETCTL (VERSATILE_SYS_BASE + VERSATILE_SYS_RESETCTL_OFFSET) -#define VERSATILE_SYS_PICCTL (VERSATILE_SYS_BASE + VERSATILE_SYS_PICCTL_OFFSET) +#define VERSATILE_SYS_PCICTL (VERSATILE_SYS_BASE + VERSATILE_SYS_PCICTL_OFFSET) #define VERSATILE_SYS_MCI (VERSATILE_SYS_BASE + VERSATILE_SYS_MCI_OFFSET) #define VERSATILE_SYS_FLASH (VERSATILE_SYS_BASE + VERSATILE_SYS_FLASH_OFFSET) #define VERSATILE_SYS_CLCD (VERSATILE_SYS_BASE + VERSATILE_SYS_CLCD_OFFSET) @@ -225,7 +225,20 @@ #define VERSATILE_SSMC_BASE 0x20000000 /* SSMC */ #define VERSATILE_IB2_BASE 0x24000000 /* IB2 module */ #define VERSATILE_MBX_BASE 0x40000000 /* MBX */ + +/* PCI space */ #define VERSATILE_PCI_BASE 0x41000000 /* PCI Interface */ +#define VERSATILE_PCI_CFG_BASE 0x42000000 +#define VERSATILE_PCI_MEM_BASE0 0x44000000 +#define VERSATILE_PCI_MEM_BASE1 0x50000000 +#define VERSATILE_PCI_MEM_BASE2 0x60000000 +/* Sizes of above maps */ +#define VERSATILE_PCI_BASE_SIZE 0x01000000 +#define VERSATILE_PCI_CFG_BASE_SIZE 0x02000000 +#define VERSATILE_PCI_MEM_BASE0_SIZE 0x0c000000 /* 32Mb */ +#define VERSATILE_PCI_MEM_BASE1_SIZE 0x10000000 /* 256Mb */ +#define VERSATILE_PCI_MEM_BASE2_SIZE 0x10000000 /* 256Mb */ + #define VERSATILE_SDRAM67_BASE 0x70000000 /* SDRAM banks 6 and 7 */ #define VERSATILE_LT_BASE 0x80000000 /* Logic Tile expansion */ -- cgit v0.10.2 From e4fe19819ef32950541503042f32e71b67edffc7 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 20 Jun 2005 18:51:07 +0100 Subject: [PATCH] ARM: 2701/1: free up ixp2000 timer 4 for the watchdog Patch from Lennert Buytenhek The IXP2000 has four timers, but if we're on an A-step IXP2800, timer 2 and 3 don't work. We need two timers for timekeeping (one for the timer interrupt and one for tracking missed jiffies), so on early IXP2800s we have no other choice but to use timer 1 and 4 for that, but on all other IXP2000s we'd rather leave timer 4 free since that's the only timer we can use for the watchdog. So, on buggy IXP2000s (i.e. the A-step IXP2800) we use timer 4 for tracking missed jiffies, and on all all non-buggy IXP2000s (i.e. everything but the A-step IXP2800) we use timer 2. On a pre-production IXP2800, this patch should print these messages on boot: Enabling IXP2800 erratum #25 workaround Unable to use IXP2000 watchdog due to IXP2800 erratum #25 On any non-buggy IXP2800 (as well as on IXP2400s) you shouldn't see anything at all, and the watchdog should be usable again. Signed-off-by: Lennert Buytenhek Signed-off-by: Deepak Saxena Signed-off-by: Russell King diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index 4f3c3d5c..fc05555 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -162,12 +162,13 @@ void __init ixp2000_map_io(void) static unsigned ticks_per_jiffy; static unsigned ticks_per_usec; static unsigned next_jiffy_time; +static volatile unsigned long *missing_jiffy_timer_csr; unsigned long ixp2000_gettimeoffset (void) { unsigned long offset; - offset = next_jiffy_time - *IXP2000_T4_CSR; + offset = next_jiffy_time - *missing_jiffy_timer_csr; return offset / ticks_per_usec; } @@ -179,7 +180,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* clear timer 1 */ ixp2000_reg_write(IXP2000_T1_CLR, 1); - while ((next_jiffy_time - *IXP2000_T4_CSR) > ticks_per_jiffy) { + while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { timer_tick(regs); next_jiffy_time -= ticks_per_jiffy; } @@ -197,20 +198,37 @@ static struct irqaction ixp2000_timer_irq = { void __init ixp2000_init_time(unsigned long tick_rate) { - ixp2000_reg_write(IXP2000_T1_CLR, 0); - ixp2000_reg_write(IXP2000_T4_CLR, 0); - ticks_per_jiffy = (tick_rate + HZ/2) / HZ; ticks_per_usec = tick_rate / 1000000; + /* + * We use timer 1 as our timer interrupt. + */ + ixp2000_reg_write(IXP2000_T1_CLR, 0); ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1); ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7)); /* - * We use T4 as a monotonic counter to track missed jiffies + * We use a second timer as a monotonic counter for tracking + * missed jiffies. The IXP2000 has four timers, but if we're + * on an A-step IXP2800, timer 2 and 3 don't work, so on those + * chips we use timer 4. Timer 4 is the only timer that can + * be used for the watchdog, so we use timer 2 if we're on a + * non-buggy chip. */ - ixp2000_reg_write(IXP2000_T4_CLD, -1); - ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); + if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) { + printk(KERN_INFO "Enabling IXP2800 erratum #25 workaround\n"); + + ixp2000_reg_write(IXP2000_T4_CLR, 0); + ixp2000_reg_write(IXP2000_T4_CLD, -1); + ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); + missing_jiffy_timer_csr = IXP2000_T4_CSR; + } else { + ixp2000_reg_write(IXP2000_T2_CLR, 0); + ixp2000_reg_write(IXP2000_T2_CLD, -1); + ixp2000_reg_write(IXP2000_T2_CTL, (1 << 7)); + missing_jiffy_timer_csr = IXP2000_T2_CSR; + } next_jiffy_time = 0xffffffff; /* register for interrupt */ diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c index ab659d3..4e98c21 100644 --- a/drivers/char/watchdog/ixp2000_wdt.c +++ b/drivers/char/watchdog/ixp2000_wdt.c @@ -192,7 +192,12 @@ static struct miscdevice ixp2000_wdt_miscdev = static int __init ixp2000_wdt_init(void) { - wdt_tick_rate = (*IXP2000_T1_CLD * HZ)/ 256;; + if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) { + printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n"); + return -EIO; + } + + wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256; return misc_register(&ixp2000_wdt_miscdev); } diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h index 6c56708..a1d9e18 100644 --- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h +++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h @@ -363,6 +363,7 @@ #define IXP2000_MIN_REV_MASK 0x0000000F #define IXP2000_PROD_ID_MASK 0xFFFFFFFF +#define IXP2000_PRODUCT_ID GLOBAL_REG(0x00) #define IXP2000_MISC_CONTROL GLOBAL_REG(0x04) #define IXP2000_MSF_CLK_CNTRL GLOBAL_REG(0x08) #define IXP2000_RESET0 GLOBAL_REG(0x0c) -- cgit v0.10.2 From d67947a1bd6530791ad3663b93d91b44de89c2ca Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 20 Jun 2005 18:51:07 +0100 Subject: [PATCH] ARM: 2716/1: SharpSL Param: Fix typo Patch from Richard Purdie Fix typo in sharpsl_param.c so it works correctly on collie. Signed-off-by: Richard Purdie Signed-off-by: Russell King diff --git a/arch/arm/common/sharpsl_param.c b/arch/arm/common/sharpsl_param.c index c2c557a..c94864c 100644 --- a/arch/arm/common/sharpsl_param.c +++ b/arch/arm/common/sharpsl_param.c @@ -22,7 +22,7 @@ * them early in the boot process, then pass them to the appropriate drivers. * Not all devices use all paramaters but the format is common to all. */ -#ifdef ARCH_SA1100 +#ifdef CONFIG_ARCH_SA1100 #define PARAM_BASE 0xe8ffc000 #else #define PARAM_BASE 0xa0000a00 -- cgit v0.10.2 From f0ffeddc897a5cc5d5c6cc1b99a8799a8b34b28f Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 20 Jun 2005 18:51:08 +0100 Subject: [PATCH] ARM: 2719/1: enable module support in ixp2000 defconfigs by default Patch from Lennert Buytenhek The ixp2000 defconfigs are among the few that do not enable module support by default. I keep enabling module support by hand for every new kernel version, so let's just make this change upstream. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King diff --git a/arch/arm/configs/enp2611_defconfig b/arch/arm/configs/enp2611_defconfig index e8f9fcc..06fae4b 100644 --- a/arch/arm/configs/enp2611_defconfig +++ b/arch/arm/configs/enp2611_defconfig @@ -50,7 +50,13 @@ CONFIG_BASE_SMALL=0 # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y # # System Type diff --git a/arch/arm/configs/ixdp2400_defconfig b/arch/arm/configs/ixdp2400_defconfig index 4fd663e..810a450 100644 --- a/arch/arm/configs/ixdp2400_defconfig +++ b/arch/arm/configs/ixdp2400_defconfig @@ -50,7 +50,13 @@ CONFIG_BASE_SMALL=0 # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y # # System Type diff --git a/arch/arm/configs/ixdp2401_defconfig b/arch/arm/configs/ixdp2401_defconfig index 6f51c98..72e1b94 100644 --- a/arch/arm/configs/ixdp2401_defconfig +++ b/arch/arm/configs/ixdp2401_defconfig @@ -50,7 +50,13 @@ CONFIG_BASE_SMALL=0 # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y # # System Type diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig index 7be3521..1592e45 100644 --- a/arch/arm/configs/ixdp2800_defconfig +++ b/arch/arm/configs/ixdp2800_defconfig @@ -50,7 +50,13 @@ CONFIG_BASE_SMALL=0 # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y # # System Type diff --git a/arch/arm/configs/ixdp2801_defconfig b/arch/arm/configs/ixdp2801_defconfig index cd84a20..f1afe3d 100644 --- a/arch/arm/configs/ixdp2801_defconfig +++ b/arch/arm/configs/ixdp2801_defconfig @@ -50,7 +50,13 @@ CONFIG_BASE_SMALL=0 # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y # # System Type -- cgit v0.10.2 From 3f7a87d2fa9b42f7aade43914f060df68cc89cc7 Mon Sep 17 00:00:00 2001 From: Frank Filz Date: Mon, 20 Jun 2005 13:14:57 -0700 Subject: [SCTP] sctp_connectx() API support Implements sctp_connectx() as defined in the SCTP sockets API draft by tunneling the request through a setsockopt(). Signed-off-by: Frank Filz Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index ebc5282..dc107ff 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -65,9 +65,11 @@ typedef enum { SCTP_CMD_TIMER_START, /* Start a timer. */ SCTP_CMD_TIMER_RESTART, /* Restart a timer. */ SCTP_CMD_TIMER_STOP, /* Stop a timer. */ - SCTP_CMD_COUNTER_RESET, /* Reset a counter. */ - SCTP_CMD_COUNTER_INC, /* Increment a counter. */ + SCTP_CMD_INIT_CHOOSE_TRANSPORT, /* Choose transport for an INIT. */ + SCTP_CMD_INIT_COUNTER_RESET, /* Reset init counter. */ + SCTP_CMD_INIT_COUNTER_INC, /* Increment init counter. */ SCTP_CMD_INIT_RESTART, /* High level, do init timer work. */ + SCTP_CMD_COOKIEECHO_RESTART, /* High level, do cookie-echo timer work. */ SCTP_CMD_INIT_FAILED, /* High level, do init failure work. */ SCTP_CMD_REPORT_DUP, /* Report a duplicate TSN. */ SCTP_CMD_STRIKE, /* Mark a strike against a transport. */ @@ -118,7 +120,6 @@ typedef union { int error; sctp_state_t state; sctp_event_timeout_t to; - sctp_counter_t counter; void *ptr; struct sctp_chunk *chunk; struct sctp_association *asoc; @@ -165,7 +166,6 @@ SCTP_ARG_CONSTRUCTOR(U16, __u16, u16) SCTP_ARG_CONSTRUCTOR(U8, __u8, u8) SCTP_ARG_CONSTRUCTOR(ERROR, int, error) SCTP_ARG_CONSTRUCTOR(STATE, sctp_state_t, state) -SCTP_ARG_CONSTRUCTOR(COUNTER, sctp_counter_t, counter) SCTP_ARG_CONSTRUCTOR(TO, sctp_event_timeout_t, to) SCTP_ARG_CONSTRUCTOR(PTR, void *, ptr) SCTP_ARG_CONSTRUCTOR(CHUNK, struct sctp_chunk *, chunk) diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 2b76c0f..4868c7f 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -263,13 +263,6 @@ enum { SCTP_MIN_PMTU = 576 }; enum { SCTP_MAX_DUP_TSNS = 16 }; enum { SCTP_MAX_GABS = 16 }; -typedef enum { - SCTP_COUNTER_INIT_ERROR, -} sctp_counter_t; - -/* How many counters does an association need? */ -#define SCTP_NUMBER_COUNTERS 5 - /* Here we define the default timers. */ /* cookie timer def = ? seconds */ diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 960abfa..ef27381 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -223,6 +223,22 @@ DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics); extern int sctp_debug_flag; #define SCTP_DEBUG_PRINTK(whatever...) \ ((void) (sctp_debug_flag && printk(KERN_DEBUG whatever))) +#define SCTP_DEBUG_PRINTK_IPADDR(lead, trail, leadparm, saddr, otherparms...) \ + if (sctp_debug_flag) { \ + if (saddr->sa.sa_family == AF_INET6) { \ + printk(KERN_DEBUG \ + lead "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" trail, \ + leadparm, \ + NIP6(saddr->v6.sin6_addr), \ + otherparms); \ + } else { \ + printk(KERN_DEBUG \ + lead "%u.%u.%u.%u" trail, \ + leadparm, \ + NIPQUAD(saddr->v4.sin_addr.s_addr), \ + otherparms); \ + } \ + } #define SCTP_ENABLE_DEBUG { sctp_debug_flag = 1; } #define SCTP_DISABLE_DEBUG { sctp_debug_flag = 0; } @@ -236,6 +252,7 @@ extern int sctp_debug_flag; #else /* SCTP_DEBUG */ #define SCTP_DEBUG_PRINTK(whatever...) +#define SCTP_DEBUG_PRINTK_IPADDR(whatever...) #define SCTP_ENABLE_DEBUG #define SCTP_DISABLE_DEBUG #define SCTP_ASSERT(expr, str, func) diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index f4fcee1..a53e08a 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -116,7 +116,8 @@ sctp_state_fn_t sctp_sf_eat_data_fast_4_4; sctp_state_fn_t sctp_sf_eat_sack_6_2; sctp_state_fn_t sctp_sf_tabort_8_4_8; sctp_state_fn_t sctp_sf_operr_notify; -sctp_state_fn_t sctp_sf_t1_timer_expire; +sctp_state_fn_t sctp_sf_t1_init_timer_expire; +sctp_state_fn_t sctp_sf_t1_cookie_timer_expire; sctp_state_fn_t sctp_sf_t2_timer_expire; sctp_state_fn_t sctp_sf_t4_timer_expire; sctp_state_fn_t sctp_sf_t5_timer_expire; @@ -258,7 +259,10 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, void sctp_chunk_assign_tsn(struct sctp_chunk *); void sctp_chunk_assign_ssn(struct sctp_chunk *); -void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error); +sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, + __u16 error, + const struct sctp_association *asoc, + struct sctp_transport *transport); /* Prototypes for statetable processing. */ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 6c24d9c..dfad4d3 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -867,10 +867,13 @@ struct sctp_transport { */ unsigned long last_time_ecne_reduced; - /* active : The current active state of this destination, - * : i.e. DOWN, UP, etc. + /* The number of times INIT has been sent on this transport. */ + int init_sent_count; + + /* state : The current state of this destination, + * : i.e. SCTP_ACTIVE, SCTP_INACTIVE, SCTP_UNKOWN. */ - int active; + int state; /* hb_allowed : The current heartbeat state of this destination, * : i.e. ALLOW-HB, NO-HEARTBEAT, etc. @@ -1222,9 +1225,6 @@ struct sctp_endpoint { /* sendbuf acct. policy. */ __u32 sndbuf_policy; - - /* Name for debugging output... */ - char *debug_name; }; /* Recover the outter endpoint structure. */ @@ -1314,11 +1314,23 @@ struct sctp_association { * : association. Normally this information is * : hashed or keyed for quick lookup and access * : of the TCB. + * : The list is also initialized with the list + * : of addresses passed with the sctp_connectx() + * : call. * * It is a list of SCTP_transport's. */ struct list_head transport_addr_list; + /* transport_count + * + * Peer : A count of the number of peer addresses + * Transport : in the Peer Transport Address List. + * Address : + * Count : + */ + __u16 transport_count; + /* port * The transport layer port number. */ @@ -1486,6 +1498,9 @@ struct sctp_association { /* Transport to which SHUTDOWN chunk was last sent. */ struct sctp_transport *shutdown_last_sent_to; + /* Transport to which INIT chunk was last sent. */ + struct sctp_transport *init_last_sent_to; + /* Next TSN : The next TSN number to be assigned to a new * : DATA chunk. This is sent in the INIT or INIT * : ACK chunk to the peer and incremented each @@ -1549,8 +1564,11 @@ struct sctp_association { /* The message size at which SCTP fragmentation will occur. */ __u32 frag_point; - /* Currently only one counter is used to count INIT errors. */ - int counters[SCTP_NUMBER_COUNTERS]; + /* Counter used to count INIT errors. */ + int init_err_counter; + + /* Count the number of INIT cycles (for doubling timeout). */ + int init_cycle; /* Default send parameters. */ __u16 default_stream; @@ -1708,6 +1726,8 @@ void sctp_association_free(struct sctp_association *); void sctp_association_put(struct sctp_association *); void sctp_association_hold(struct sctp_association *); +struct sctp_transport *sctp_assoc_choose_init_transport( + struct sctp_association *); struct sctp_transport *sctp_assoc_choose_shutdown_transport( struct sctp_association *); void sctp_assoc_update_retran_path(struct sctp_association *); @@ -1717,9 +1737,12 @@ int sctp_assoc_lookup_laddr(struct sctp_association *asoc, const union sctp_addr *laddr); struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *, const union sctp_addr *address, - const int gfp); + const int gfp, + const int peer_state); void sctp_assoc_del_peer(struct sctp_association *asoc, const union sctp_addr *addr); +void sctp_assoc_rm_peer(struct sctp_association *asoc, + struct sctp_transport *peer); void sctp_assoc_control_transport(struct sctp_association *, struct sctp_transport *, sctp_transport_cmd_t, sctp_sn_error_t); diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 2758e8c..f6328ae 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -111,6 +111,8 @@ enum sctp_optname { #define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS + SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ +#define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX }; /* @@ -527,6 +529,7 @@ struct sctp_paddrinfo { enum sctp_spinfo_state { SCTP_INACTIVE, SCTP_ACTIVE, + SCTP_UNKNOWN = 0xffff /* Value used for transport state unknown */ }; /* diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 663843d..7ae6aa7 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -191,10 +191,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->last_cwr_tsn = asoc->ctsn_ack_point; asoc->unack_data = 0; - SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n", - asoc->ep->debug_name, - asoc->ctsn_ack_point); - /* ADDIP Section 4.1 Asconf Chunk Procedures * * When an endpoint has an ASCONF signaled change to be sent to the @@ -211,6 +207,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a /* Make an empty list of remote transport addresses. */ INIT_LIST_HEAD(&asoc->peer.transport_addr_list); + asoc->peer.transport_count = 0; /* RFC 2960 5.1 Normal Establishment of an Association * @@ -288,6 +285,7 @@ struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep, asoc->base.malloced = 1; SCTP_DBG_OBJCNT_INC(assoc); + SCTP_DEBUG_PRINTK("Created asoc %p\n", asoc); return asoc; @@ -356,6 +354,8 @@ void sctp_association_free(struct sctp_association *asoc) sctp_transport_free(transport); } + asoc->peer.transport_count = 0; + /* Free any cached ASCONF_ACK chunk. */ if (asoc->addip_last_asconf_ack) sctp_chunk_free(asoc->addip_last_asconf_ack); @@ -400,7 +400,7 @@ void sctp_assoc_set_primary(struct sctp_association *asoc, /* If the primary path is changing, assume that the * user wants to use this new path. */ - if (transport->active) + if (transport->state != SCTP_INACTIVE) asoc->peer.active_path = transport; /* @@ -428,10 +428,58 @@ void sctp_assoc_set_primary(struct sctp_association *asoc, transport->cacc.next_tsn_at_change = asoc->next_tsn; } +/* Remove a transport from an association. */ +void sctp_assoc_rm_peer(struct sctp_association *asoc, + struct sctp_transport *peer) +{ + struct list_head *pos; + struct sctp_transport *transport; + + SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_rm_peer:association %p addr: ", + " port: %d\n", + asoc, + (&peer->ipaddr), + peer->ipaddr.v4.sin_port); + + /* If we are to remove the current retran_path, update it + * to the next peer before removing this peer from the list. + */ + if (asoc->peer.retran_path == peer) + sctp_assoc_update_retran_path(asoc); + + /* Remove this peer from the list. */ + list_del(&peer->transports); + + /* Get the first transport of asoc. */ + pos = asoc->peer.transport_addr_list.next; + transport = list_entry(pos, struct sctp_transport, transports); + + /* Update any entries that match the peer to be deleted. */ + if (asoc->peer.primary_path == peer) + sctp_assoc_set_primary(asoc, transport); + if (asoc->peer.active_path == peer) + asoc->peer.active_path = transport; + if (asoc->peer.last_data_from == peer) + asoc->peer.last_data_from = transport; + + /* If we remove the transport an INIT was last sent to, set it to + * NULL. Combined with the update of the retran path above, this + * will cause the next INIT to be sent to the next available + * transport, maintaining the cycle. + */ + if (asoc->init_last_sent_to == peer) + asoc->init_last_sent_to = NULL; + + asoc->peer.transport_count--; + + sctp_transport_free(peer); +} + /* Add a transport address to an association. */ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, const union sctp_addr *addr, - int gfp) + const int gfp, + const int peer_state) { struct sctp_transport *peer; struct sctp_sock *sp; @@ -442,14 +490,25 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, /* AF_INET and AF_INET6 share common port field. */ port = addr->v4.sin_port; + SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_add_peer:association %p addr: ", + " port: %d state:%s\n", + asoc, + addr, + addr->v4.sin_port, + peer_state == SCTP_UNKNOWN?"UNKNOWN":"ACTIVE"); + /* Set the port if it has not been set yet. */ if (0 == asoc->peer.port) asoc->peer.port = port; /* Check to see if this is a duplicate. */ peer = sctp_assoc_lookup_paddr(asoc, addr); - if (peer) + if (peer) { + if (peer_state == SCTP_ACTIVE && + peer->state == SCTP_UNKNOWN) + peer->state = SCTP_ACTIVE; return peer; + } peer = sctp_transport_new(addr, gfp); if (!peer) @@ -516,8 +575,12 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, /* Set the transport's RTO.initial value */ peer->rto = asoc->rto_initial; + /* Set the peer's active state. */ + peer->state = peer_state; + /* Attach the remote transport to our asoc. */ list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); + asoc->peer.transport_count++; /* If we do not yet have a primary path, set one. */ if (!asoc->peer.primary_path) { @@ -525,8 +588,9 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, asoc->peer.retran_path = peer; } - if (asoc->peer.active_path == asoc->peer.retran_path) + if (asoc->peer.active_path == asoc->peer.retran_path) { asoc->peer.retran_path = peer; + } return peer; } @@ -537,37 +601,16 @@ void sctp_assoc_del_peer(struct sctp_association *asoc, { struct list_head *pos; struct list_head *temp; - struct sctp_transport *peer = NULL; struct sctp_transport *transport; list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); if (sctp_cmp_addr_exact(addr, &transport->ipaddr)) { - peer = transport; - list_del(pos); + /* Do book keeping for removing the peer and free it. */ + sctp_assoc_rm_peer(asoc, transport); break; } } - - /* The address we want delete is not in the association. */ - if (!peer) - return; - - /* Get the first transport of asoc. */ - pos = asoc->peer.transport_addr_list.next; - transport = list_entry(pos, struct sctp_transport, transports); - - /* Update any entries that match the peer to be deleted. */ - if (asoc->peer.primary_path == peer) - sctp_assoc_set_primary(asoc, transport); - if (asoc->peer.active_path == peer) - asoc->peer.active_path = transport; - if (asoc->peer.retran_path == peer) - asoc->peer.retran_path = transport; - if (asoc->peer.last_data_from == peer) - asoc->peer.last_data_from = transport; - - sctp_transport_free(peer); } /* Lookup a transport by address. */ @@ -608,12 +651,12 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, /* Record the transition on the transport. */ switch (command) { case SCTP_TRANSPORT_UP: - transport->active = SCTP_ACTIVE; + transport->state = SCTP_ACTIVE; spc_state = SCTP_ADDR_AVAILABLE; break; case SCTP_TRANSPORT_DOWN: - transport->active = SCTP_INACTIVE; + transport->state = SCTP_INACTIVE; spc_state = SCTP_ADDR_UNREACHABLE; break; @@ -643,7 +686,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, list_for_each(pos, &asoc->peer.transport_addr_list) { t = list_entry(pos, struct sctp_transport, transports); - if (!t->active) + if (t->state == SCTP_INACTIVE) continue; if (!first || t->last_time_heard > first->last_time_heard) { second = first; @@ -663,7 +706,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, * [If the primary is active but not most recent, bump the most * recently used transport.] */ - if (asoc->peer.primary_path->active && + if (asoc->peer.primary_path->state != SCTP_INACTIVE && first != asoc->peer.primary_path) { second = first; first = asoc->peer.primary_path; @@ -958,7 +1001,7 @@ void sctp_assoc_update(struct sctp_association *asoc, transports); if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr)) sctp_assoc_add_peer(asoc, &trans->ipaddr, - GFP_ATOMIC); + GFP_ATOMIC, SCTP_ACTIVE); } asoc->ctsn_ack_point = asoc->next_tsn - 1; @@ -998,7 +1041,7 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc) /* Try to find an active transport. */ - if (t->active) { + if (t->state != SCTP_INACTIVE) { break; } else { /* Keep track of the next transport in case @@ -1019,6 +1062,40 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc) } asoc->peer.retran_path = t; + + SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association" + " %p addr: ", + " port: %d\n", + asoc, + (&t->ipaddr), + t->ipaddr.v4.sin_port); +} + +/* Choose the transport for sending a INIT packet. */ +struct sctp_transport *sctp_assoc_choose_init_transport( + struct sctp_association *asoc) +{ + struct sctp_transport *t; + + /* Use the retran path. If the last INIT was sent over the + * retran path, update the retran path and use it. + */ + if (!asoc->init_last_sent_to) { + t = asoc->peer.active_path; + } else { + if (asoc->init_last_sent_to == asoc->peer.retran_path) + sctp_assoc_update_retran_path(asoc); + t = asoc->peer.retran_path; + } + + SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association" + " %p addr: ", + " port: %d\n", + asoc, + (&t->ipaddr), + t->ipaddr.v4.sin_port); + + return t; } /* Choose the transport for sending a SHUTDOWN packet. */ diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 334f617..2ec0320 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -134,7 +134,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ep->last_key = ep->current_key = 0; ep->key_changed_at = jiffies; - ep->debug_name = "unnamedEndpoint"; return ep; } diff --git a/net/sctp/input.c b/net/sctp/input.c index fffc880..339f7ac 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -353,7 +353,7 @@ void sctp_icmp_proto_unreachable(struct sock *sk, sctp_do_sm(SCTP_EVENT_T_OTHER, SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH), - asoc->state, asoc->ep, asoc, NULL, + asoc->state, asoc->ep, asoc, t, GFP_ATOMIC); } diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 1b2d4adc..4eb81a1 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -682,9 +682,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) if (!new_transport) { new_transport = asoc->peer.active_path; - } else if (!new_transport->active) { - /* If the chunk is Heartbeat or Heartbeat Ack, - * send it to chunk->transport, even if it's + } else if (new_transport->state == SCTP_INACTIVE) { + /* If the chunk is Heartbeat or Heartbeat Ack, + * send it to chunk->transport, even if it's * inactive. * * 3.3.6 Heartbeat Acknowledgement: @@ -840,7 +840,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) * Otherwise, we want to use the active path. */ new_transport = chunk->transport; - if (!new_transport || !new_transport->active) + if (!new_transport || + new_transport->state == SCTP_INACTIVE) new_transport = asoc->peer.active_path; /* Change packets if necessary. */ @@ -1454,7 +1455,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, /* Mark the destination transport address as * active if it is not so marked. */ - if (!transport->active) { + if (transport->state == SCTP_INACTIVE) { sctp_assoc_control_transport( transport->asoc, transport, diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 33ac8bf..5baed9b 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1830,7 +1830,7 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, * be a a better choice than any of the embedded addresses. */ if (peer_addr) - if(!sctp_assoc_add_peer(asoc, peer_addr, gfp)) + if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE)) goto nomem; /* Process the initialization parameters. */ @@ -1841,6 +1841,14 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, goto clean_up; } + /* Walk list of transports, removing transports in the UNKNOWN state. */ + list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, struct sctp_transport, transports); + if (transport->state == SCTP_UNKNOWN) { + sctp_assoc_rm_peer(asoc, transport); + } + } + /* The fixed INIT headers are always in network byte * order. */ @@ -1906,7 +1914,8 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, * stream sequence number shall be set to 0. */ - /* Allocate storage for the negotiated streams if it is not a temporary * association. + /* Allocate storage for the negotiated streams if it is not a temporary + * association. */ if (!asoc->temp) { int assoc_id; @@ -1952,6 +1961,9 @@ clean_up: list_del_init(pos); sctp_transport_free(transport); } + + asoc->peer.transport_count = 0; + nomem: return 0; } @@ -1995,7 +2007,7 @@ static int sctp_process_param(struct sctp_association *asoc, af->from_addr_param(&addr, param.addr, asoc->peer.port, 0); scope = sctp_scope(peer_addr); if (sctp_in_scope(&addr, scope)) - if (!sctp_assoc_add_peer(asoc, &addr, gfp)) + if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_ACTIVE)) return 0; break; @@ -2396,7 +2408,7 @@ static __u16 sctp_process_asconf_param(struct sctp_association *asoc, * Due to Resource Shortage'. */ - peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC); + peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC, SCTP_ACTIVE); if (!peer) return SCTP_ERROR_RSRC_LOW; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index f65fa44..778639d 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -414,11 +414,13 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc, */ asoc->overall_error_count++; - if (transport->active && + if (transport->state != SCTP_INACTIVE && (transport->error_count++ >= transport->max_retrans)) { - SCTP_DEBUG_PRINTK("transport_strike: transport " - "IP:%d.%d.%d.%d failed.\n", - NIPQUAD(transport->ipaddr.v4.sin_addr)); + SCTP_DEBUG_PRINTK_IPADDR("transport_strike:association %p", + " transport IP: port:%d failed.\n", + asoc, + (&transport->ipaddr), + transport->ipaddr.v4.sin_port); sctp_assoc_control_transport(asoc, transport, SCTP_TRANSPORT_DOWN, SCTP_FAILED_THRESHOLD); @@ -593,7 +595,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, /* Mark the destination transport address as active if it is not so * marked. */ - if (!t->active) + if (t->state == SCTP_INACTIVE) sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP, SCTP_HEARTBEAT_SUCCESS); @@ -665,8 +667,11 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, asoc->state = state; + SCTP_DEBUG_PRINTK("sctp_cmd_new_state: asoc %p[%s]\n", + asoc, sctp_state_tbl[state]); + if (sctp_style(sk, TCP)) { - /* Change the sk->sk_state of a TCP-style socket that has + /* Change the sk->sk_state of a TCP-style socket that has * sucessfully completed a connect() call. */ if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED)) @@ -678,6 +683,16 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sk->sk_shutdown |= RCV_SHUTDOWN; } + if (sctp_state(asoc, COOKIE_WAIT)) { + /* Reset init timeouts since they may have been + * increased due to timer expirations. + */ + asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = + asoc->ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT]; + asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = + asoc->ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE]; + } + if (sctp_state(asoc, ESTABLISHED) || sctp_state(asoc, CLOSED) || sctp_state(asoc, SHUTDOWN_RECEIVED)) { @@ -1120,10 +1135,10 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, * to be executed only during failed attempts of * association establishment. */ - if ((asoc->peer.retran_path != - asoc->peer.primary_path) && - (asoc->counters[SCTP_COUNTER_INIT_ERROR] > 0)) { - sctp_add_cmd_sf(commands, + if ((asoc->peer.retran_path != + asoc->peer.primary_path) && + (asoc->init_err_counter > 0)) { + sctp_add_cmd_sf(commands, SCTP_CMD_FORCE_PRIM_RETRAN, SCTP_NULL()); } @@ -1237,18 +1252,67 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, sctp_association_put(asoc); break; + case SCTP_CMD_INIT_CHOOSE_TRANSPORT: + chunk = cmd->obj.ptr; + t = sctp_assoc_choose_init_transport(asoc); + asoc->init_last_sent_to = t; + chunk->transport = t; + t->init_sent_count++; + break; + case SCTP_CMD_INIT_RESTART: /* Do the needed accounting and updates * associated with restarting an initialization - * timer. + * timer. Only multiply the timeout by two if + * all transports have been tried at the current + * timeout. + */ + t = asoc->init_last_sent_to; + asoc->init_err_counter++; + + if (t->init_sent_count > (asoc->init_cycle + 1)) { + asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] *= 2; + if (asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] > + asoc->max_init_timeo) { + asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = + asoc->max_init_timeo; + } + asoc->init_cycle++; + SCTP_DEBUG_PRINTK( + "T1 INIT Timeout adjustment" + " init_err_counter: %d" + " cycle: %d" + " timeout: %d\n", + asoc->init_err_counter, + asoc->init_cycle, + asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT]); + } + + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + break; + + case SCTP_CMD_COOKIEECHO_RESTART: + /* Do the needed accounting and updates + * associated with restarting an initialization + * timer. Only multiply the timeout by two if + * all transports have been tried at the current + * timeout. */ - asoc->counters[SCTP_COUNTER_INIT_ERROR]++; - asoc->timeouts[cmd->obj.to] *= 2; - if (asoc->timeouts[cmd->obj.to] > + asoc->init_err_counter++; + + asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] *= 2; + if (asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] > asoc->max_init_timeo) { - asoc->timeouts[cmd->obj.to] = + asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = asoc->max_init_timeo; } + SCTP_DEBUG_PRINTK( + "T1 COOKIE Timeout adjustment" + " init_err_counter: %d" + " timeout: %d\n", + asoc->init_err_counter, + asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE]); /* If we've sent any data bundled with * COOKIE-ECHO we need to resend. @@ -1261,7 +1325,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, - SCTP_TO(cmd->obj.to)); + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); break; case SCTP_CMD_INIT_FAILED: @@ -1273,12 +1337,13 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, subtype, chunk, cmd->obj.u32); break; - case SCTP_CMD_COUNTER_INC: - asoc->counters[cmd->obj.counter]++; + case SCTP_CMD_INIT_COUNTER_INC: + asoc->init_err_counter++; break; - case SCTP_CMD_COUNTER_RESET: - asoc->counters[cmd->obj.counter] = 0; + case SCTP_CMD_INIT_COUNTER_RESET: + asoc->init_err_counter = 0; + asoc->init_cycle = 0; break; case SCTP_CMD_REPORT_DUP: diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 8e01b8f..0581896 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -533,6 +533,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_PEER_INIT, SCTP_PEER_INIT(initchunk)); + /* Reset init error count upon receipt of INIT-ACK. */ + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_COUNTER_RESET, SCTP_NULL()); + /* 5.1 C) "A" shall stop the T1-init timer and leave * COOKIE-WAIT state. "A" shall then ... start the T1-cookie * timer, and enter the COOKIE-ECHOED state. @@ -775,8 +778,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep, * from the COOKIE-ECHOED state to the COOKIE-WAIT * state is performed. */ - sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET, - SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_COUNTER_RESET, SCTP_NULL()); /* RFC 2960 5.1 Normal Establishment of an Association * @@ -1019,10 +1021,22 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, link = sctp_assoc_lookup_paddr(asoc, &from_addr); /* This should never happen, but lets log it if so. */ - if (!link) { - printk(KERN_WARNING - "%s: Could not find address %d.%d.%d.%d\n", - __FUNCTION__, NIPQUAD(from_addr.v4.sin_addr)); + if (unlikely(!link)) { + if (from_addr.sa.sa_family == AF_INET6) { + printk(KERN_WARNING + "%s association %p could not find address " + "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + __FUNCTION__, + asoc, + NIP6(from_addr.v6.sin6_addr)); + } else { + printk(KERN_WARNING + "%s association %p could not find address " + "%u.%u.%u.%u\n", + __FUNCTION__, + asoc, + NIPQUAD(from_addr.v4.sin_addr.s_addr)); + } return SCTP_DISPOSITION_DISCARD; } @@ -2095,9 +2109,7 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep, sctp_errhdr_t *err; struct sctp_chunk *reply; struct sctp_bind_addr *bp; - int attempts; - - attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1; + int attempts = asoc->init_err_counter + 1; if (attempts >= asoc->max_init_attempts) { sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, @@ -2157,8 +2169,7 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep, /* Cast away the const modifier, as we want to just * rerun it through as a sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_INC, - SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_COUNTER_INC, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); @@ -2281,8 +2292,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep, if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) error = ((sctp_errhdr_t *)chunk->skb->data)->cause; - sctp_stop_t1_and_abort(commands, error); - return SCTP_DISPOSITION_ABORT; + return sctp_stop_t1_and_abort(commands, error, asoc, chunk->transport); } /* @@ -2294,8 +2304,8 @@ sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep void *arg, sctp_cmd_seq_t *commands) { - sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR); - return SCTP_DISPOSITION_ABORT; + return sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR, asoc, + (struct sctp_transport *)arg); } /* @@ -2318,8 +2328,12 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep, * * This is common code called by several sctp_sf_*_abort() functions above. */ -void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error) +sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, + __u16 error, + const struct sctp_association *asoc, + struct sctp_transport *transport) { + SCTP_DEBUG_PRINTK("ABORT received (INIT).\n"); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); SCTP_INC_STATS(SCTP_MIB_ABORTEDS); @@ -2328,6 +2342,7 @@ void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error) /* CMD_INIT_FAILED will DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(error)); + return SCTP_DISPOSITION_ABORT; } /* @@ -3805,6 +3820,10 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC((struct sctp_association *) asoc)); + /* Choose transport for INIT. */ + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_CHOOSE_TRANSPORT, + SCTP_CHUNK(repl)); + /* After sending the INIT, "A" starts the T1-init timer and * enters the COOKIE-WAIT state. */ @@ -4589,7 +4608,7 @@ sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep, } /* - * sctp_sf_t1_timer_expire + * sctp_sf_t1_init_timer_expire * * Section: 4 Note: 2 * Verification Tag: @@ -4603,7 +4622,59 @@ sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep, * endpoint MUST abort the initialization process and report the * error to SCTP user. * - * 3) If the T1-cookie timer expires, the endpoint MUST retransmit + * Outputs + * (timers, events) + * + */ +sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + struct sctp_chunk *repl = NULL; + struct sctp_bind_addr *bp; + int attempts = asoc->init_err_counter + 1; + + SCTP_DEBUG_PRINTK("Timer T1 expired (INIT).\n"); + + if (attempts < asoc->max_init_attempts) { + bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; + repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0); + if (!repl) + return SCTP_DISPOSITION_NOMEM; + + /* Choose transport for INIT. */ + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_CHOOSE_TRANSPORT, + SCTP_CHUNK(repl)); + + /* Issue a sideeffect to do the needed accounting. */ + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + } else { + SCTP_DEBUG_PRINTK("Giving up on INIT, attempts: %d" + " max_init_attempts: %d\n", + attempts, asoc->max_init_attempts); + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, + SCTP_U32(SCTP_ERROR_NO_ERROR)); + return SCTP_DISPOSITION_DELETE_TCB; + } + + return SCTP_DISPOSITION_CONSUME; +} + +/* + * sctp_sf_t1_cookie_timer_expire + * + * Section: 4 Note: 2 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * RFC 2960 Section 4 Notes + * 3) If the T1-cookie timer expires, the endpoint MUST retransmit * COOKIE ECHO and re-start the T1-cookie timer without changing * state. This MUST be repeated up to 'Max.Init.Retransmits' times. * After that, the endpoint MUST abort the initialization process and @@ -4613,46 +4684,26 @@ sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep, * (timers, events) * */ -sctp_disposition_t sctp_sf_t1_timer_expire(const struct sctp_endpoint *ep, +sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep, const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - struct sctp_chunk *repl; - struct sctp_bind_addr *bp; - sctp_event_timeout_t timer = (sctp_event_timeout_t) arg; - int timeout; - int attempts; - - timeout = asoc->timeouts[timer]; - attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1; - repl = NULL; + struct sctp_chunk *repl = NULL; + int attempts = asoc->init_err_counter + 1; - SCTP_DEBUG_PRINTK("Timer T1 expired.\n"); + SCTP_DEBUG_PRINTK("Timer T1 expired (COOKIE-ECHO).\n"); if (attempts < asoc->max_init_attempts) { - switch (timer) { - case SCTP_EVENT_TIMEOUT_T1_INIT: - bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; - repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0); - break; - - case SCTP_EVENT_TIMEOUT_T1_COOKIE: - repl = sctp_make_cookie_echo(asoc, NULL); - break; - - default: - BUG(); - break; - }; - + repl = sctp_make_cookie_echo(asoc, NULL); if (!repl) - goto nomem; + return SCTP_DISPOSITION_NOMEM; /* Issue a sideeffect to do the needed accounting. */ - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_RESTART, - SCTP_TO(timer)); + sctp_add_cmd_sf(commands, SCTP_CMD_COOKIEECHO_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); } else { sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, @@ -4661,9 +4712,6 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const struct sctp_endpoint *ep, } return SCTP_DISPOSITION_CONSUME; - -nomem: - return SCTP_DISPOSITION_NOMEM; } /* RFC2960 9.2 If the timer expires, the endpoint must re-send the SHUTDOWN diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 8967846..75ef104 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -783,7 +783,8 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ /* SCTP_STATE_COOKIE_WAIT */ \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ /* SCTP_STATE_COOKIE_ECHOED */ \ - {.fn = sctp_sf_t1_timer_expire, .name = "sctp_sf_t1_timer_expire"}, \ + {.fn = sctp_sf_t1_cookie_timer_expire, \ + .name = "sctp_sf_t1_cookie_timer_expire"}, \ /* SCTP_STATE_ESTABLISHED */ \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ @@ -802,7 +803,8 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ /* SCTP_STATE_CLOSED */ \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ - {.fn = sctp_sf_t1_timer_expire, .name = "sctp_sf_t1_timer_expire"}, \ + {.fn = sctp_sf_t1_init_timer_expire, \ + .name = "sctp_sf_t1_init_timer_expire"}, \ /* SCTP_STATE_COOKIE_ECHOED */ \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_ESTABLISHED */ \ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index e6926cb..aad55dc 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -262,18 +262,18 @@ static struct sctp_transport *sctp_addr_id2transport(struct sock *sk, * sockaddr_in6 [RFC 2553]), * addr_len - the size of the address structure. */ -SCTP_STATIC int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) +SCTP_STATIC int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len) { int retval = 0; sctp_lock_sock(sk); - SCTP_DEBUG_PRINTK("sctp_bind(sk: %p, uaddr: %p, addr_len: %d)\n", - sk, uaddr, addr_len); + SCTP_DEBUG_PRINTK("sctp_bind(sk: %p, addr: %p, addr_len: %d)\n", + sk, addr, addr_len); /* Disallow binding twice. */ if (!sctp_sk(sk)->ep->base.bind_addr.port) - retval = sctp_do_bind(sk, (union sctp_addr *)uaddr, + retval = sctp_do_bind(sk, (union sctp_addr *)addr, addr_len); else retval = -EINVAL; @@ -318,23 +318,27 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) unsigned short snum; int ret = 0; - SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, len: %d)\n", - sk, addr, len); - /* Common sockaddr verification. */ af = sctp_sockaddr_af(sp, addr, len); - if (!af) + if (!af) { + SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, len: %d) EINVAL\n", + sk, addr, len); return -EINVAL; + } + + snum = ntohs(addr->v4.sin_port); + + SCTP_DEBUG_PRINTK_IPADDR("sctp_do_bind(sk: %p, new addr: ", + ", port: %d, new port: %d, len: %d)\n", + sk, + addr, + bp->port, snum, + len); /* PF specific bind() address verification. */ if (!sp->pf->bind_verify(sp, addr)) return -EADDRNOTAVAIL; - snum= ntohs(addr->v4.sin_port); - - SCTP_DEBUG_PRINTK("sctp_do_bind: port: %d, new port: %d\n", - bp->port, snum); - /* We must either be unbound, or bind to the same port. */ if (bp->port && (snum != bp->port)) { SCTP_DEBUG_PRINTK("sctp_do_bind:" @@ -816,7 +820,8 @@ out: * * Basically do nothing but copying the addresses from user to kernel * land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk. - * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() * from userspace. + * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() + * from userspace. * * We don't use copy_from_user() for optimization: we first do the * sanity checks (buffer size -fast- and access check-healthy @@ -913,6 +918,243 @@ out: return err; } +/* __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, int addrs_size) + * + * Common routine for handling connect() and sctp_connectx(). + * Connect will come in with just a single address. + */ +static int __sctp_connect(struct sock* sk, + struct sockaddr *kaddrs, + int addrs_size) +{ + struct sctp_sock *sp; + struct sctp_endpoint *ep; + struct sctp_association *asoc = NULL; + struct sctp_association *asoc2; + struct sctp_transport *transport; + union sctp_addr to; + struct sctp_af *af; + sctp_scope_t scope; + long timeo; + int err = 0; + int addrcnt = 0; + int walk_size = 0; + struct sockaddr *sa_addr; + void *addr_buf; + + sp = sctp_sk(sk); + ep = sp->ep; + + /* connect() cannot be done on a socket that is already in ESTABLISHED + * state - UDP-style peeled off socket or a TCP-style socket that + * is already connected. + * It cannot be done even on a TCP-style listening socket. + */ + if (sctp_sstate(sk, ESTABLISHED) || + (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) { + err = -EISCONN; + goto out_free; + } + + /* Walk through the addrs buffer and count the number of addresses. */ + addr_buf = kaddrs; + while (walk_size < addrs_size) { + sa_addr = (struct sockaddr *)addr_buf; + af = sctp_get_af_specific(sa_addr->sa_family); + + /* If the address family is not supported or if this address + * causes the address buffer to overflow return EINVAL. + */ + if (!af || (walk_size + af->sockaddr_len) > addrs_size) { + err = -EINVAL; + goto out_free; + } + + err = sctp_verify_addr(sk, (union sctp_addr *)sa_addr, + af->sockaddr_len); + if (err) + goto out_free; + + memcpy(&to, sa_addr, af->sockaddr_len); + to.v4.sin_port = ntohs(to.v4.sin_port); + + /* Check if there already is a matching association on the + * endpoint (other than the one created here). + */ + asoc2 = sctp_endpoint_lookup_assoc(ep, &to, &transport); + if (asoc2 && asoc2 != asoc) { + if (asoc2->state >= SCTP_STATE_ESTABLISHED) + err = -EISCONN; + else + err = -EALREADY; + goto out_free; + } + + /* If we could not find a matching association on the endpoint, + * make sure that there is no peeled-off association matching + * the peer address even on another socket. + */ + if (sctp_endpoint_is_peeled_off(ep, &to)) { + err = -EADDRNOTAVAIL; + goto out_free; + } + + if (!asoc) { + /* If a bind() or sctp_bindx() is not called prior to + * an sctp_connectx() call, the system picks an + * ephemeral port and will choose an address set + * equivalent to binding with a wildcard address. + */ + if (!ep->base.bind_addr.port) { + if (sctp_autobind(sk)) { + err = -EAGAIN; + goto out_free; + } + } + + scope = sctp_scope(&to); + asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); + if (!asoc) { + err = -ENOMEM; + goto out_free; + } + } + + /* Prime the peer's transport structures. */ + transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL, + SCTP_UNKNOWN); + if (!transport) { + err = -ENOMEM; + goto out_free; + } + + addrcnt++; + addr_buf += af->sockaddr_len; + walk_size += af->sockaddr_len; + } + + err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL); + if (err < 0) { + goto out_free; + } + + err = sctp_primitive_ASSOCIATE(asoc, NULL); + if (err < 0) { + goto out_free; + } + + /* Initialize sk's dport and daddr for getpeername() */ + inet_sk(sk)->dport = htons(asoc->peer.port); + af = sctp_get_af_specific(to.sa.sa_family); + af->to_sk_daddr(&to, sk); + + timeo = sock_sndtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK); + err = sctp_wait_for_connect(asoc, &timeo); + + /* Don't free association on exit. */ + asoc = NULL; + +out_free: + + SCTP_DEBUG_PRINTK("About to exit __sctp_connect() free asoc: %p" + " kaddrs: %p err: %d\n", + asoc, kaddrs, err); + if (asoc) + sctp_association_free(asoc); + return err; +} + +/* Helper for tunneling sctp_connectx() requests through sctp_setsockopt() + * + * API 8.9 + * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt); + * + * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. + * If the sd is an IPv6 socket, the addresses passed can either be IPv4 + * or IPv6 addresses. + * + * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see + * Section 3.1.2 for this usage. + * + * addrs is a pointer to an array of one or more socket addresses. Each + * address is contained in its appropriate structure (i.e. struct + * sockaddr_in or struct sockaddr_in6) the family of the address type + * must be used to distengish the address length (note that this + * representation is termed a "packed array" of addresses). The caller + * specifies the number of addresses in the array with addrcnt. + * + * On success, sctp_connectx() returns 0. On failure, sctp_connectx() returns + * -1, and sets errno to the appropriate error code. + * + * For SCTP, the port given in each socket address must be the same, or + * sctp_connectx() will fail, setting errno to EINVAL. + * + * An application can use sctp_connectx to initiate an association with + * an endpoint that is multi-homed. Much like sctp_bindx() this call + * allows a caller to specify multiple addresses at which a peer can be + * reached. The way the SCTP stack uses the list of addresses to set up + * the association is implementation dependant. This function only + * specifies that the stack will try to make use of all the addresses in + * the list when needed. + * + * Note that the list of addresses passed in is only used for setting up + * the association. It does not necessarily equal the set of addresses + * the peer uses for the resulting association. If the caller wants to + * find out the set of peer addresses, it must use sctp_getpaddrs() to + * retrieve them after the association has been set up. + * + * Basically do nothing but copying the addresses from user to kernel + * land and invoking either sctp_connectx(). This is used for tunneling + * the sctp_connectx() request through sctp_setsockopt() from userspace. + * + * We don't use copy_from_user() for optimization: we first do the + * sanity checks (buffer size -fast- and access check-healthy + * pointer); if all of those succeed, then we can alloc the memory + * (expensive operation) needed to copy the data to kernel. Then we do + * the copying without checking the user space area + * (__copy_from_user()). + * + * On exit there is no need to do sockfd_put(), sys_setsockopt() does + * it. + * + * sk The sk of the socket + * addrs The pointer to the addresses in user land + * addrssize Size of the addrs buffer + * + * Returns 0 if ok, <0 errno code on error. + */ +SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, + struct sockaddr __user *addrs, + int addrs_size) +{ + int err = 0; + struct sockaddr *kaddrs; + + SCTP_DEBUG_PRINTK("%s - sk %p addrs %p addrs_size %d\n", + __FUNCTION__, sk, addrs, addrs_size); + + if (unlikely(addrs_size <= 0)) + return -EINVAL; + + /* Check the user passed a healthy pointer. */ + if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size))) + return -EFAULT; + + /* Alloc space for the address array in kernel memory. */ + kaddrs = (struct sockaddr *)kmalloc(addrs_size, GFP_KERNEL); + if (unlikely(!kaddrs)) + return -ENOMEM; + + if (__copy_from_user(kaddrs, addrs, addrs_size)) { + err = -EFAULT; + } else { + err = __sctp_connect(sk, kaddrs, addrs_size); + } + + kfree(kaddrs); + return err; +} + /* API 3.1.4 close() - UDP Style Syntax * Applications use close() to perform graceful shutdown (as described in * Section 10.1 of [SCTP]) on ALL the associations currently represented @@ -1095,7 +1337,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, sp = sctp_sk(sk); ep = sp->ep; - SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name); + SCTP_DEBUG_PRINTK("Using endpoint: %p.\n", ep); /* We cannot send a message over a TCP-style listening socket. */ if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) { @@ -1306,7 +1548,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, } /* Prime the peer's transport structures. */ - transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL); + transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL, SCTP_UNKNOWN); if (!transport) { err = -ENOMEM; goto out_free; @@ -2208,6 +2450,12 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, optlen, SCTP_BINDX_REM_ADDR); break; + case SCTP_SOCKOPT_CONNECTX: + /* 'optlen' is the size of the addresses buffer. */ + retval = sctp_setsockopt_connectx(sk, (struct sockaddr __user *)optval, + optlen); + break; + case SCTP_DISABLE_FRAGMENTS: retval = sctp_setsockopt_disable_fragments(sk, optval, optlen); break; @@ -2283,112 +2531,29 @@ out_nounlock: * * len: the size of the address. */ -SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, +SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr, int addr_len) { - struct sctp_sock *sp; - struct sctp_endpoint *ep; - struct sctp_association *asoc; - struct sctp_transport *transport; - union sctp_addr to; - struct sctp_af *af; - sctp_scope_t scope; - long timeo; int err = 0; + struct sctp_af *af; sctp_lock_sock(sk); - SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d)\n", - __FUNCTION__, sk, uaddr, addr_len); - - sp = sctp_sk(sk); - ep = sp->ep; - - /* connect() cannot be done on a socket that is already in ESTABLISHED - * state - UDP-style peeled off socket or a TCP-style socket that - * is already connected. - * It cannot be done even on a TCP-style listening socket. - */ - if (sctp_sstate(sk, ESTABLISHED) || - (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) { - err = -EISCONN; - goto out_unlock; - } - - err = sctp_verify_addr(sk, (union sctp_addr *)uaddr, addr_len); - if (err) - goto out_unlock; - - if (addr_len > sizeof(to)) - addr_len = sizeof(to); - memcpy(&to, uaddr, addr_len); - to.v4.sin_port = ntohs(to.v4.sin_port); - - asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); - if (asoc) { - if (asoc->state >= SCTP_STATE_ESTABLISHED) - err = -EISCONN; - else - err = -EALREADY; - goto out_unlock; - } - - /* If we could not find a matching association on the endpoint, - * make sure that there is no peeled-off association matching the - * peer address even on another socket. - */ - if (sctp_endpoint_is_peeled_off(ep, &to)) { - err = -EADDRNOTAVAIL; - goto out_unlock; - } - - /* If a bind() or sctp_bindx() is not called prior to a connect() - * call, the system picks an ephemeral port and will choose an address - * set equivalent to binding with a wildcard address. - */ - if (!ep->base.bind_addr.port) { - if (sctp_autobind(sk)) { - err = -EAGAIN; - goto out_unlock; - } - } - - scope = sctp_scope(&to); - asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); - if (!asoc) { - err = -ENOMEM; - goto out_unlock; - } + SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d\n", + __FUNCTION__, sk, addr, addr_len); - /* Prime the peer's transport structures. */ - transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL); - if (!transport) { - sctp_association_free(asoc); - goto out_unlock; - } - err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL); - if (err < 0) { - sctp_association_free(asoc); - goto out_unlock; - } - - err = sctp_primitive_ASSOCIATE(asoc, NULL); - if (err < 0) { - sctp_association_free(asoc); - goto out_unlock; + /* Validate addr_len before calling common connect/connectx routine. */ + af = sctp_get_af_specific(addr->sa_family); + if (!af || addr_len < af->sockaddr_len) { + err = -EINVAL; + } else { + /* Pass correct addr len to common routine (so it knows there + * is only one address being passed. + */ + err = __sctp_connect(sk, addr, af->sockaddr_len); } - /* Initialize sk's dport and daddr for getpeername() */ - inet_sk(sk)->dport = htons(asoc->peer.port); - af = sctp_get_af_specific(to.sa.sa_family); - af->to_sk_daddr(&to, sk); - - timeo = sock_sndtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK); - err = sctp_wait_for_connect(asoc, &timeo); - -out_unlock: sctp_release_sock(sk); - return err; } @@ -2677,12 +2842,15 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, /* Map ipv4 address into v4-mapped-on-v6 address. */ sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), (union sctp_addr *)&status.sstat_primary.spinfo_address); - status.sstat_primary.spinfo_state = transport->active; + status.sstat_primary.spinfo_state = transport->state; status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_srtt = transport->srtt; status.sstat_primary.spinfo_rto = jiffies_to_msecs(transport->rto); status.sstat_primary.spinfo_mtu = transport->pmtu; + if (status.sstat_primary.spinfo_state == SCTP_UNKNOWN) + status.sstat_primary.spinfo_state = SCTP_ACTIVE; + if (put_user(len, optlen)) { retval = -EFAULT; goto out; @@ -2733,12 +2901,15 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, return -EINVAL; pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc); - pinfo.spinfo_state = transport->active; + pinfo.spinfo_state = transport->state; pinfo.spinfo_cwnd = transport->cwnd; pinfo.spinfo_srtt = transport->srtt; pinfo.spinfo_rto = jiffies_to_msecs(transport->rto); pinfo.spinfo_mtu = transport->pmtu; + if (pinfo.spinfo_state == SCTP_UNKNOWN) + pinfo.spinfo_state = SCTP_ACTIVE; + if (put_user(len, optlen)) { retval = -EFAULT; goto out; @@ -3591,7 +3762,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, int retval = 0; int len; - SCTP_DEBUG_PRINTK("sctp_getsockopt(sk: %p, ...)\n", sk); + SCTP_DEBUG_PRINTK("sctp_getsockopt(sk: %p... optname: %d)\n", + sk, optname); /* I can hardly begin to describe how wrong this is. This is * so broken as to be worse than useless. The API draft @@ -4596,8 +4768,7 @@ out: return err; do_error: - if (asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1 >= - asoc->max_init_attempts) + if (asoc->init_err_counter + 1 >= asoc->max_init_attempts) err = -ETIMEDOUT; else err = -ECONNREFUSED; diff --git a/net/sctp/transport.c b/net/sctp/transport.c index f30882e..0ec0fde 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -83,7 +83,9 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, peer->last_time_used = jiffies; peer->last_time_ecne_reduced = jiffies; - peer->active = SCTP_ACTIVE; + peer->init_sent_count = 0; + + peer->state = SCTP_ACTIVE; peer->hb_allowed = 0; /* Initialize the default path max_retrans. */ -- cgit v0.10.2 From 72cb6962a91f2af9eef69a06198e1949c10259ae Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 20 Jun 2005 13:18:08 -0700 Subject: [IPSEC]: Add xfrm_init_state This patch adds xfrm_init_state which is simply a wrapper that calls xfrm_get_type and subsequently x->type->init_state. It also gets rid of the unused args argument. Abstracting it out allows us to add common initialisation code, e.g., to set family-specific flags. The add_time setting in xfrm_user.c was deleted because it's already set by xfrm_state_alloc. Signed-off-by: Herbert Xu Acked-by: James Morris Signed-off-by: David S. Miller diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 0e65e02..77bfdde 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -225,7 +225,7 @@ struct xfrm_type struct module *owner; __u8 proto; - int (*init_state)(struct xfrm_state *x, void *args); + int (*init_state)(struct xfrm_state *x); void (*destructor)(struct xfrm_state *); int (*input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb); int (*post_input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb); @@ -839,6 +839,7 @@ extern int xfrm_replay_check(struct xfrm_state *x, u32 seq); extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq); extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); +extern int xfrm_init_state(struct xfrm_state *x); extern int xfrm4_rcv(struct sk_buff *skb); extern int xfrm4_output(struct sk_buff *skb); extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 0e98f22..514c85b 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -200,7 +200,7 @@ static void ah4_err(struct sk_buff *skb, u32 info) xfrm_state_put(x); } -static int ah_init_state(struct xfrm_state *x, void *args) +static int ah_init_state(struct xfrm_state *x) { struct ah_data *ahp = NULL; struct xfrm_algo_desc *aalg_desc; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index eae84cc..ba57446 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -362,7 +362,7 @@ static void esp_destroy(struct xfrm_state *x) kfree(esp); } -static int esp_init_state(struct xfrm_state *x, void *args) +static int esp_init_state(struct xfrm_state *x) { struct esp_data *esp = NULL; diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 1a23c52..2065944 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -236,15 +236,10 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) t->props.mode = 1; t->props.saddr.a4 = x->props.saddr.a4; t->props.flags = x->props.flags; - - t->type = xfrm_get_type(IPPROTO_IPIP, t->props.family); - if (t->type == NULL) - goto error; - - if (t->type->init_state(t, NULL)) + + if (xfrm_init_state(t)) goto error; - t->km.state = XFRM_STATE_VALID; atomic_set(&t->tunnel_users, 1); out: return t; @@ -422,7 +417,7 @@ static void ipcomp_destroy(struct xfrm_state *x) kfree(ipcd); } -static int ipcomp_init_state(struct xfrm_state *x, void *args) +static int ipcomp_init_state(struct xfrm_state *x) { int err; struct ipcomp_data *ipcd; diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index 413191f..e1fe360 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -84,7 +84,7 @@ static void ipip_err(struct sk_buff *skb, u32 info) handler->err_handler(skb, &arg); } -static int ipip_init_state(struct xfrm_state *x, void *args) +static int ipip_init_state(struct xfrm_state *x) { if (!x->props.mode) return -EINVAL; diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index e3ecf62..986fdfd 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -339,7 +339,7 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, xfrm_state_put(x); } -static int ah6_init_state(struct xfrm_state *x, void *args) +static int ah6_init_state(struct xfrm_state *x) { struct ah_data *ahp = NULL; struct xfrm_algo_desc *aalg_desc; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index be7095d..324db62 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -296,7 +296,7 @@ static void esp6_destroy(struct xfrm_state *x) kfree(esp); } -static int esp6_init_state(struct xfrm_state *x, void *args) +static int esp6_init_state(struct xfrm_state *x) { struct esp_data *esp = NULL; diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 6cde531..423feb4 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -234,14 +234,9 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) t->props.mode = 1; memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); - t->type = xfrm_get_type(IPPROTO_IPV6, t->props.family); - if (t->type == NULL) + if (xfrm_init_state(t)) goto error; - if (t->type->init_state(t, NULL)) - goto error; - - t->km.state = XFRM_STATE_VALID; atomic_set(&t->tunnel_users, 1); out: @@ -420,7 +415,7 @@ static void ipcomp6_destroy(struct xfrm_state *x) xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); } -static int ipcomp6_init_state(struct xfrm_state *x, void *args) +static int ipcomp6_init_state(struct xfrm_state *x) { int err; struct ipcomp_data *ipcd; diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index ffcadd6..60c26c8 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -466,7 +466,7 @@ static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; } -static int xfrm6_tunnel_init_state(struct xfrm_state *x, void *args) +static int xfrm6_tunnel_init_state(struct xfrm_state *x) { if (!x->props.mode) return -EINVAL; diff --git a/net/key/af_key.c b/net/key/af_key.c index 98b72f2..652dd09 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1096,17 +1096,11 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, } } - x->type = xfrm_get_type(proto, x->props.family); - if (x->type == NULL) { - err = -ENOPROTOOPT; - goto out; - } - if (x->type->init_state(x, NULL)) { - err = -EINVAL; + err = xfrm_init_state(x); + if (err) goto out; - } + x->km.seq = hdr->sadb_msg_seq; - x->km.state = XFRM_STATE_VALID; return x; out: diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 0a42607..d65ed86 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -118,7 +118,6 @@ retry: xfrm_policy_put_afinfo(afinfo); return type; } -EXPORT_SYMBOL(xfrm_get_type); int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 2537f26..1845b73 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1055,6 +1055,27 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu) } EXPORT_SYMBOL(xfrm_state_mtu); + +int xfrm_init_state(struct xfrm_state *x) +{ + int err; + + err = -ENOENT; + x->type = xfrm_get_type(x->id.proto, x->props.family); + if (x->type == NULL) + goto error; + + err = x->type->init_state(x); + if (err) + goto error; + + x->km.state = XFRM_STATE_VALID; + +error: + return err; +} + +EXPORT_SYMBOL(xfrm_init_state); void __init xfrm_state_init(void) { diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 5ce8558..ecade48 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -249,17 +249,10 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) goto error; - err = -ENOENT; - x->type = xfrm_get_type(x->id.proto, x->props.family); - if (x->type == NULL) - goto error; - - err = x->type->init_state(x, NULL); + err = xfrm_init_state(x); if (err) goto error; - x->curlft.add_time = (unsigned long) xtime.tv_sec; - x->km.state = XFRM_STATE_VALID; x->km.seq = p->seq; return x; -- cgit v0.10.2 From d094cd83c06e06e01d8edb540555f3f64e4081c2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 20 Jun 2005 13:19:41 -0700 Subject: [IPSEC]: Add xfrm_state_afinfo->init_flags This patch adds the xfrm_state_afinfo->init_flags hook which allows each address family to perform any common initialisation that does not require a corresponding destructor call. It will be used subsequently to set the XFRM_STATE_NOPMTUDISC flag in IPv4. It also fixes up the error codes returned by xfrm_init_state. Signed-off-by: Herbert Xu Acked-by: James Morris Signed-off-by: David S. Miller diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 77bfdde..029522a 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -204,6 +204,7 @@ struct xfrm_state_afinfo { rwlock_t lock; struct list_head *state_bydst; struct list_head *state_byspi; + int (*init_flags)(struct xfrm_state *x); void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl, struct xfrm_tmpl *tmpl, xfrm_address_t *daddr, xfrm_address_t *saddr); diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 1845b73..9d206c2 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1058,10 +1058,26 @@ EXPORT_SYMBOL(xfrm_state_mtu); int xfrm_init_state(struct xfrm_state *x) { + struct xfrm_state_afinfo *afinfo; + int family = x->props.family; int err; - err = -ENOENT; - x->type = xfrm_get_type(x->id.proto, x->props.family); + err = -EAFNOSUPPORT; + afinfo = xfrm_state_get_afinfo(family); + if (!afinfo) + goto error; + + err = 0; + if (afinfo->init_flags) + err = afinfo->init_flags(x); + + xfrm_state_put_afinfo(afinfo); + + if (err) + goto error; + + err = -EPROTONOSUPPORT; + x->type = xfrm_get_type(x->id.proto, family); if (x->type == NULL) goto error; -- cgit v0.10.2 From dd87147eed934eaff92869f3d158697c7239d1d2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 20 Jun 2005 13:21:43 -0700 Subject: [IPSEC]: Add XFRM_STATE_NOPMTUDISC flag This patch adds the flag XFRM_STATE_NOPMTUDISC for xfrm states. It is similar to the nopmtudisc on IPIP/GRE tunnels. It only has an effect on IPv4 tunnel mode states. For these states, it will ensure that the DF flag is always cleared. This is primarily useful to work around ICMP blackholes. In future this flag could also allow a larger MTU to be set within the tunnel just like IPIP/GRE tunnels. This could be useful for short haul tunnels where temporary fragmentation outside the tunnel is desired over smaller fragments inside the tunnel. Signed-off-by: Herbert Xu Acked-by: James Morris Signed-off-by: David S. Miller diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index e6b5192..7240667 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -245,6 +245,7 @@ struct sadb_x_nat_t_port { /* Security Association flags */ #define SADB_SAFLAGS_PFS 1 +#define SADB_SAFLAGS_NOPMTUDISC 0x20000000 #define SADB_SAFLAGS_DECAP_DSCP 0x40000000 #define SADB_SAFLAGS_NOECN 0x80000000 diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index d68391a..f0d4233 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -196,6 +196,7 @@ struct xfrm_usersa_info { __u8 flags; #define XFRM_STATE_NOECN 1 #define XFRM_STATE_DECAP_DSCP 2 +#define XFRM_STATE_NOPMTUDISC 4 }; struct xfrm_usersa_id { diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index af2392a..66620a9 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -33,6 +33,7 @@ static void xfrm4_encap(struct sk_buff *skb) struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; struct iphdr *iph, *top_iph; + int flags; iph = skb->nh.iph; skb->h.ipiph = iph; @@ -51,10 +52,13 @@ static void xfrm4_encap(struct sk_buff *skb) /* DS disclosed */ top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); - if (x->props.flags & XFRM_STATE_NOECN) + + flags = x->props.flags; + if (flags & XFRM_STATE_NOECN) IP_ECN_clear(top_iph); - top_iph->frag_off = iph->frag_off & htons(IP_DF); + top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? + 0 : (iph->frag_off & htons(IP_DF)); if (!top_iph->frag_off) __ip_select_ident(top_iph, dst, 0); diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 223a2e8..050611d 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c @@ -7,12 +7,20 @@ * */ +#include #include #include #include static struct xfrm_state_afinfo xfrm4_state_afinfo; +static int xfrm4_init_flags(struct xfrm_state *x) +{ + if (ipv4_config.no_pmtu_disc) + x->props.flags |= XFRM_STATE_NOPMTUDISC; + return 0; +} + static void __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, struct xfrm_tmpl *tmpl, @@ -109,6 +117,7 @@ __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, static struct xfrm_state_afinfo xfrm4_state_afinfo = { .family = AF_INET, .lock = RW_LOCK_UNLOCKED, + .init_flags = xfrm4_init_flags, .init_tempsel = __xfrm4_init_tempsel, .state_lookup = __xfrm4_state_lookup, .find_acq = __xfrm4_find_acq, diff --git a/net/key/af_key.c b/net/key/af_key.c index 652dd09..4879743 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -690,6 +690,8 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN; if (x->props.flags & XFRM_STATE_DECAP_DSCP) sa->sadb_sa_flags |= SADB_SAFLAGS_DECAP_DSCP; + if (x->props.flags & XFRM_STATE_NOPMTUDISC) + sa->sadb_sa_flags |= SADB_SAFLAGS_NOPMTUDISC; /* hard time */ if (hsc & 2) { @@ -974,6 +976,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, x->props.flags |= XFRM_STATE_NOECN; if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP) x->props.flags |= XFRM_STATE_DECAP_DSCP; + if (sa->sadb_sa_flags & SADB_SAFLAGS_NOPMTUDISC) + x->props.flags |= XFRM_STATE_NOPMTUDISC; lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1]; if (lifetime != NULL) { -- cgit v0.10.2 From f852640e74f71e6dd38146e1149ec1fe6da2fb07 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 20 Jun 2005 13:31:11 -0700 Subject: [AX25]: endian-annotate ax25_type_trans() Signed-off-by: Alexey Dobriyan Acked-by: Ralf Baechle Signed-off-by: David S. Miller diff --git a/include/net/ax25.h b/include/net/ax25.h index 9e6368a..828a3a93 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -220,7 +220,7 @@ static __inline__ void ax25_cb_put(ax25_cb *ax25) } } -static inline unsigned short ax25_type_trans(struct sk_buff *skb, struct net_device *dev) +static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev) { skb->dev = dev; skb->pkt_type = PACKET_HOST; -- cgit v0.10.2 From f6e276ee67c0ac9efafd24bc6f7a84aa359656df Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 20 Jun 2005 13:32:05 -0700 Subject: [ATALK]: endian annotations Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/include/linux/atalk.h b/include/linux/atalk.h index 31d3fc2..09a1451 100644 --- a/include/linux/atalk.h +++ b/include/linux/atalk.h @@ -20,7 +20,7 @@ #define SIOCATALKDIFADDR (SIOCPROTOPRIVATE + 0) struct atalk_addr { - __u16 s_net; + __be16 s_net; __u8 s_node; }; @@ -33,8 +33,8 @@ struct sockaddr_at { struct atalk_netrange { __u8 nr_phase; - __u16 nr_firstnet; - __u16 nr_lastnet; + __be16 nr_firstnet; + __be16 nr_lastnet; }; #ifdef __KERNEL__ @@ -70,8 +70,8 @@ struct atalk_iface { struct atalk_sock { /* struct sock has to be the first member of atalk_sock */ struct sock sk; - unsigned short dest_net; - unsigned short src_net; + __be16 dest_net; + __be16 src_net; unsigned char dest_node; unsigned char src_node; unsigned char dest_port; @@ -95,9 +95,9 @@ struct ddpehdr { deh_hops:4, deh_len:10; #endif - __u16 deh_sum; - __u16 deh_dnet; - __u16 deh_snet; + __be16 deh_sum; + __be16 deh_dnet; + __be16 deh_snet; __u8 deh_dnode; __u8 deh_snode; __u8 deh_dport; @@ -142,24 +142,24 @@ struct ddpshdr { /* AppleTalk AARP headers */ struct elapaarp { - __u16 hw_type; + __be16 hw_type; #define AARP_HW_TYPE_ETHERNET 1 #define AARP_HW_TYPE_TOKENRING 2 - __u16 pa_type; + __be16 pa_type; __u8 hw_len; __u8 pa_len; #define AARP_PA_ALEN 4 - __u16 function; + __be16 function; #define AARP_REQUEST 1 #define AARP_REPLY 2 #define AARP_PROBE 3 __u8 hw_src[ETH_ALEN] __attribute__ ((packed)); __u8 pa_src_zero __attribute__ ((packed)); - __u16 pa_src_net __attribute__ ((packed)); + __be16 pa_src_net __attribute__ ((packed)); __u8 pa_src_node __attribute__ ((packed)); __u8 hw_dst[ETH_ALEN] __attribute__ ((packed)); __u8 pa_dst_zero __attribute__ ((packed)); - __u16 pa_dst_net __attribute__ ((packed)); + __be16 pa_dst_net __attribute__ ((packed)); __u8 pa_dst_node __attribute__ ((packed)); }; diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 54640c0..10d0404 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -565,7 +565,7 @@ int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb, * numbers we just happen to need. Now put the * length in the lower two. */ - *((__u16 *)skb->data) = htons(skb->len); + *((__be16 *)skb->data) = htons(skb->len); ft = 1; } /* diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 876dbac..192b529 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -401,7 +401,7 @@ out_err: } /* Find a match for a specific network:node pair */ -static struct atalk_iface *atalk_find_interface(int net, int node) +static struct atalk_iface *atalk_find_interface(__be16 net, int node) { struct atalk_iface *iface; -- cgit v0.10.2 From 246955fe4c38bd706ae30e37c64892c94213775d Mon Sep 17 00:00:00 2001 From: Robert Olsson Date: Mon, 20 Jun 2005 13:36:39 -0700 Subject: [NETLINK]: fib_lookup() via netlink Below is a more generic patch to do fib_lookup via netlink. For others we should say that we discussed this as a way to verify route selection. It's also possible there are others uses for this. In short the fist half of struct fib_result_nl is filled in by caller and netlink call fills in the other half and returns it. In case anyone is interested there is a corresponding user app to compare the full routing table this was used to test implementation of the LC-trie. Signed-off-by: David S. Miller diff --git a/include/linux/netlink.h b/include/linux/netlink.h index e38407a..561d4dc 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -14,6 +14,7 @@ #define NETLINK_SELINUX 7 /* SELinux event notifications */ #define NETLINK_ARPD 8 #define NETLINK_AUDIT 9 /* auditing */ +#define NETLINK_FIB_LOOKUP 10 #define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */ #define NETLINK_IP6_FW 13 #define NETLINK_DNRTMSG 14 /* DECnet routing messages */ diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index e5a5f6b..a4208a3 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -109,6 +109,20 @@ struct fib_result { #endif }; +struct fib_result_nl { + u32 fl_addr; /* To be looked up*/ + u32 fl_fwmark; + unsigned char fl_tos; + unsigned char fl_scope; + unsigned char tb_id_in; + + unsigned char tb_id; /* Results */ + unsigned char prefixlen; + unsigned char nh_sel; + unsigned char type; + unsigned char scope; + int err; +}; #ifdef CONFIG_IP_ROUTE_MULTIPATH diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 563e7d6..cd8e45a 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -516,6 +516,60 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) #undef BRD1_OK } +static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb ) +{ + + struct fib_result res; + struct flowi fl = { .nl_u = { .ip4_u = { .daddr = frn->fl_addr, + .fwmark = frn->fl_fwmark, + .tos = frn->fl_tos, + .scope = frn->fl_scope } } }; + if (tb) { + local_bh_disable(); + + frn->tb_id = tb->tb_id; + frn->err = tb->tb_lookup(tb, &fl, &res); + + if (!frn->err) { + frn->prefixlen = res.prefixlen; + frn->nh_sel = res.nh_sel; + frn->type = res.type; + frn->scope = res.scope; + } + local_bh_enable(); + } +} + +static void nl_fib_input(struct sock *sk, int len) +{ + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh = NULL; + struct fib_result_nl *frn; + int err; + u32 pid; + struct fib_table *tb; + + skb = skb_recv_datagram(sk, 0, 0, &err); + nlh = (struct nlmsghdr *)skb->data; + + frn = (struct fib_result_nl *) NLMSG_DATA(nlh); + tb = fib_get_table(frn->tb_id_in); + + nl_fib_lookup(frn, tb); + + pid = nlh->nlmsg_pid; /*pid of sending process */ + NETLINK_CB(skb).groups = 0; /* not in mcast group */ + NETLINK_CB(skb).pid = 0; /* from kernel */ + NETLINK_CB(skb).dst_pid = pid; + NETLINK_CB(skb).dst_groups = 0; /* unicast */ + netlink_unicast(sk, skb, pid, MSG_DONTWAIT); +} + +static void nl_fib_lookup_init(void) +{ + netlink_kernel_create(NETLINK_FIB_LOOKUP, nl_fib_input); +} + static void fib_disable_ip(struct net_device *dev, int force) { if (fib_sync_down(0, dev, force)) @@ -604,6 +658,7 @@ void __init ip_fib_init(void) register_netdevice_notifier(&fib_netdev_notifier); register_inetaddr_notifier(&fib_inetaddr_notifier); + nl_fib_lookup_init(); } EXPORT_SYMBOL(inet_addr_type); -- cgit v0.10.2 From eb11d8ffceead1eb3d84366f1687daf2217e883e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 26 Apr 2005 02:29:58 -0500 Subject: [PATCH] kobject_hotplug() should use kobject_name() kobject: kobject_hotplug should use kobject_name() instead of accessing kobj->name directly since for objects with long names it can contain garbage. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 2a4e767..1ede5aa 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -246,7 +246,7 @@ void kobject_hotplug(struct kobject *kobj, enum kobject_action action) if (hotplug_ops->name) name = hotplug_ops->name(kset, kobj); if (name == NULL) - name = kset->kobj.name; + name = kobject_name(&kset->kobj); argv [0] = hotplug_path; argv [1] = name; -- cgit v0.10.2 From e3a15db2415579d5136b9ba9b52fe27c66da8780 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 26 Apr 2005 02:31:08 -0500 Subject: [PATCH] sysfs_{create|remove}_link should take const char * sysfs: make sysfs_{create|remove}_link to take const char * name. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index dfdf701..fae57c8 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -43,7 +43,7 @@ static void fill_object_path(struct kobject * kobj, char * buffer, int length) } } -static int sysfs_add_link(struct dentry * parent, char * name, struct kobject * target) +static int sysfs_add_link(struct dentry * parent, const char * name, struct kobject * target) { struct sysfs_dirent * parent_sd = parent->d_fsdata; struct sysfs_symlink * sl; @@ -79,7 +79,7 @@ exit1: * @target: object we're pointing to. * @name: name of the symlink. */ -int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name) +int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) { struct dentry * dentry = kobj->dentry; int error = 0; @@ -99,13 +99,13 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * nam * @name: name of the symlink to remove. */ -void sysfs_remove_link(struct kobject * kobj, char * name) +void sysfs_remove_link(struct kobject * kobj, const char * name) { sysfs_hash_and_remove(kobj->dentry,name); } static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target, - char *path) + char *path) { char * s; int depth, size; diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 38b58b3..931b5aa 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -105,11 +105,11 @@ sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode); extern void sysfs_remove_file(struct kobject *, const struct attribute *); -extern int -sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name); +extern int +sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name); extern void -sysfs_remove_link(struct kobject *, char * name); +sysfs_remove_link(struct kobject *, const char * name); int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr); int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr); @@ -153,12 +153,12 @@ static inline void sysfs_remove_file(struct kobject * k, const struct attribute ; } -static inline int sysfs_create_link(struct kobject * k, struct kobject * t, char * n) +static inline int sysfs_create_link(struct kobject * k, struct kobject * t, const char * n) { return 0; } -static inline void sysfs_remove_link(struct kobject * k, char * name) +static inline void sysfs_remove_link(struct kobject * k, const char * name) { ; } -- cgit v0.10.2 From f3b4f3c6dec04c6c8261fe22645f07b39976595a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 26 Apr 2005 02:32:00 -0500 Subject: [PATCH] Make kobject's name be const char * kobject: make kobject's name const char * since users should not attempt to change it (except by calling kobject_rename). Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 765d660..76dc672 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -33,7 +33,7 @@ extern u64 hotplug_seqnum; struct kobject { - char * k_name; + const char * k_name; char name[KOBJ_NAME_LEN]; struct kref kref; struct list_head entry; @@ -46,7 +46,7 @@ struct kobject { extern int kobject_set_name(struct kobject *, const char *, ...) __attribute__((format(printf,2,3))); -static inline char * kobject_name(struct kobject * kobj) +static inline const char * kobject_name(const struct kobject * kobj) { return kobj->k_name; } @@ -57,7 +57,7 @@ extern void kobject_cleanup(struct kobject *); extern int kobject_add(struct kobject *); extern void kobject_del(struct kobject *); -extern int kobject_rename(struct kobject *, char *new_name); +extern int kobject_rename(struct kobject *, const char *new_name); extern int kobject_register(struct kobject *); extern void kobject_unregister(struct kobject *); diff --git a/lib/kobject.c b/lib/kobject.c index 9404882..dd0917d 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -279,7 +279,7 @@ EXPORT_SYMBOL(kobject_set_name); * @new_name: object's new name */ -int kobject_rename(struct kobject * kobj, char *new_name) +int kobject_rename(struct kobject * kobj, const char *new_name) { int error = 0; diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 1ede5aa..8e49d21 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -197,7 +197,7 @@ void kobject_hotplug(struct kobject *kobj, enum kobject_action action) int i = 0; int retval; char *kobj_path = NULL; - char *name = NULL; + const char *name = NULL; char *action_string; u64 seq; struct kobject *top_kobj = kobj; @@ -249,7 +249,7 @@ void kobject_hotplug(struct kobject *kobj, enum kobject_action action) name = kobject_name(&kset->kobj); argv [0] = hotplug_path; - argv [1] = name; + argv [1] = (char *)name; /* won't be changed but 'const' has to go */ argv [2] = NULL; /* minimal command environment */ -- cgit v0.10.2 From 419cab3fc69588ebe35b845cc3a584ae172463de Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 26 Apr 2005 02:32:54 -0500 Subject: [PATCH] kset_hotplug_ops->name shoudl return const char * kobject: change name() method in kset_hotplug_ops return const char * since users shoudl not try to modify returned data. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/class.c b/drivers/base/class.c index d2a2f8f..ff33ebb 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -262,7 +262,7 @@ static int class_hotplug_filter(struct kset *kset, struct kobject *kobj) return 0; } -static char *class_hotplug_name(struct kset *kset, struct kobject *kobj) +static const char *class_hotplug_name(struct kset *kset, struct kobject *kobj) { struct class_device *class_dev = to_class_dev(kobj); diff --git a/drivers/base/core.c b/drivers/base/core.c index fbc2234..32f3f09 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -102,7 +102,7 @@ static int dev_hotplug_filter(struct kset *kset, struct kobject *kobj) return 0; } -static char *dev_hotplug_name(struct kset *kset, struct kobject *kobj) +static const char *dev_hotplug_name(struct kset *kset, struct kobject *kobj) { struct device *dev = to_dev(kobj); diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 76dc672..3b22304 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -94,7 +94,7 @@ struct kobj_type { */ struct kset_hotplug_ops { int (*filter)(struct kset *kset, struct kobject *kobj); - char *(*name)(struct kset *kset, struct kobject *kobj); + const char *(*name)(struct kset *kset, struct kobject *kobj); int (*hotplug)(struct kset *kset, struct kobject *kobj, char **envp, int num_envp, char *buffer, int buffer_size); }; -- cgit v0.10.2 From 8d790d74085833ba2a3e84b5bcd683be4981c29a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 26 Apr 2005 02:34:05 -0500 Subject: [PATCH] make driver's name be const char * Driver core: change driver's, bus's, class's and platform device's names to be const char * so one can use const char *drv_name = "asdfg"; when initializing structures. Also kill couple of whitespaces. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index ef0b357..83e815d 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -239,7 +239,7 @@ static char *usb_dump_interface_descriptor(char *start, char *end, int setno) { const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc; - char *driver_name = ""; + const char *driver_name = ""; if (start > end) return start; diff --git a/include/linux/device.h b/include/linux/device.h index df94c0d..fa9e6ca 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -47,7 +47,7 @@ struct class_device; struct class_simple; struct bus_type { - char * name; + const char * name; struct subsystem subsys; struct kset drivers; @@ -98,17 +98,17 @@ extern int bus_create_file(struct bus_type *, struct bus_attribute *); extern void bus_remove_file(struct bus_type *, struct bus_attribute *); struct device_driver { - char * name; + const char * name; struct bus_type * bus; struct completion unloaded; struct kobject kobj; struct list_head devices; - struct module * owner; + struct module * owner; int (*probe) (struct device * dev); - int (*remove) (struct device * dev); + int (*remove) (struct device * dev); void (*shutdown) (struct device * dev); int (*suspend) (struct device * dev, pm_message_t state, u32 level); int (*resume) (struct device * dev, u32 level); @@ -142,7 +142,7 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute * * device classes */ struct class { - char * name; + const char * name; struct subsystem subsys; struct list_head children; @@ -366,7 +366,7 @@ extern struct device *device_find(const char *name, struct bus_type *bus); /* drivers/base/platform.c */ struct platform_device { - char * name; + const char * name; u32 id; struct device dev; u32 num_resources; -- cgit v0.10.2 From d48593bf208e0d046c35fb0707ae5b23fef8c4ff Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 29 Apr 2005 00:58:46 -0500 Subject: [PATCH] Make attributes names const char * sysfs: make attributes and attribute_group's names const char * Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 3a413f7..5febd6d 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -40,9 +40,7 @@ struct ib_port { struct kobject kobj; struct ib_device *ibdev; struct attribute_group gid_group; - struct attribute **gid_attr; struct attribute_group pkey_group; - struct attribute **pkey_attr; u8 port_num; }; @@ -60,8 +58,9 @@ struct port_attribute port_attr_##_name = __ATTR(_name, _mode, _show, _store) struct port_attribute port_attr_##_name = __ATTR_RO(_name) struct port_table_attribute { - struct port_attribute attr; - int index; + struct port_attribute attr; + char name[8]; + int index; }; static ssize_t port_attr_show(struct kobject *kobj, @@ -398,17 +397,16 @@ static void ib_port_release(struct kobject *kobj) struct attribute *a; int i; - for (i = 0; (a = p->gid_attr[i]); ++i) { - kfree(a->name); + for (i = 0; (a = p->gid_group.attrs[i]); ++i) kfree(a); - } - for (i = 0; (a = p->pkey_attr[i]); ++i) { - kfree(a->name); + kfree(p->gid_group.attrs); + + for (i = 0; (a = p->pkey_group.attrs[i]); ++i) kfree(a); - } - kfree(p->gid_attr); + kfree(p->pkey_group.attrs); + kfree(p); } @@ -449,58 +447,45 @@ static int ib_device_hotplug(struct class_device *cdev, char **envp, return 0; } -static int alloc_group(struct attribute ***attr, - ssize_t (*show)(struct ib_port *, - struct port_attribute *, char *buf), - int len) +static struct attribute ** +alloc_group_attrs(ssize_t (*show)(struct ib_port *, + struct port_attribute *, char *buf), + int len) { - struct port_table_attribute ***tab_attr = - (struct port_table_attribute ***) attr; + struct attribute **tab_attr; + struct port_table_attribute *element; int i; - int ret; - - *tab_attr = kmalloc((1 + len) * sizeof *tab_attr, GFP_KERNEL); - if (!*tab_attr) - return -ENOMEM; - memset(*tab_attr, 0, (1 + len) * sizeof *tab_attr); + tab_attr = kcalloc(1 + len, sizeof(struct attribute *), GFP_KERNEL); + if (!tab_attr) + return NULL; - for (i = 0; i < len; ++i) { - (*tab_attr)[i] = kmalloc(sizeof *(*tab_attr)[i], GFP_KERNEL); - if (!(*tab_attr)[i]) { - ret = -ENOMEM; + for (i = 0; i < len; i++) { + element = kcalloc(1, sizeof(struct port_table_attribute), + GFP_KERNEL); + if (!element) goto err; - } - memset((*tab_attr)[i], 0, sizeof *(*tab_attr)[i]); - (*tab_attr)[i]->attr.attr.name = kmalloc(8, GFP_KERNEL); - if (!(*tab_attr)[i]->attr.attr.name) { - ret = -ENOMEM; - goto err; - } - if (snprintf((*tab_attr)[i]->attr.attr.name, 8, "%d", i) >= 8) { - ret = -ENOMEM; + if (snprintf(element->name, sizeof(element->name), + "%d", i) >= sizeof(element->name)) goto err; - } - (*tab_attr)[i]->attr.attr.mode = S_IRUGO; - (*tab_attr)[i]->attr.attr.owner = THIS_MODULE; - (*tab_attr)[i]->attr.show = show; - (*tab_attr)[i]->index = i; - } - - return 0; + element->attr.attr.name = element->name; + element->attr.attr.mode = S_IRUGO; + element->attr.attr.owner = THIS_MODULE; + element->attr.show = show; + element->index = i; -err: - for (i = 0; i < len; ++i) { - if ((*tab_attr)[i]) - kfree((*tab_attr)[i]->attr.attr.name); - kfree((*tab_attr)[i]); + tab_attr[i] = &element->attr.attr; } - kfree(*tab_attr); + return tab_attr; - return ret; +err: + while (--i >= 0) + kfree(tab_attr[i]); + kfree(tab_attr); + return NULL; } static int add_port(struct ib_device *device, int port_num) @@ -541,23 +526,20 @@ static int add_port(struct ib_device *device, int port_num) if (ret) goto err_put; - ret = alloc_group(&p->gid_attr, show_port_gid, attr.gid_tbl_len); - if (ret) - goto err_remove_pma; - p->gid_group.name = "gids"; - p->gid_group.attrs = p->gid_attr; + p->gid_group.attrs = alloc_group_attrs(show_port_gid, attr.gid_tbl_len); + if (!p->gid_group.attrs) + goto err_remove_pma; ret = sysfs_create_group(&p->kobj, &p->gid_group); if (ret) goto err_free_gid; - ret = alloc_group(&p->pkey_attr, show_port_pkey, attr.pkey_tbl_len); - if (ret) - goto err_remove_gid; - p->pkey_group.name = "pkeys"; - p->pkey_group.attrs = p->pkey_attr; + p->pkey_group.attrs = alloc_group_attrs(show_port_pkey, + attr.pkey_tbl_len); + if (!p->pkey_group.attrs) + goto err_remove_gid; ret = sysfs_create_group(&p->kobj, &p->pkey_group); if (ret) @@ -568,23 +550,19 @@ static int add_port(struct ib_device *device, int port_num) return 0; err_free_pkey: - for (i = 0; i < attr.pkey_tbl_len; ++i) { - kfree(p->pkey_attr[i]->name); - kfree(p->pkey_attr[i]); - } + for (i = 0; i < attr.pkey_tbl_len; ++i) + kfree(p->pkey_group.attrs[i]); - kfree(p->pkey_attr); + kfree(p->pkey_group.attrs); err_remove_gid: sysfs_remove_group(&p->kobj, &p->gid_group); err_free_gid: - for (i = 0; i < attr.gid_tbl_len; ++i) { - kfree(p->gid_attr[i]->name); - kfree(p->gid_attr[i]); - } + for (i = 0; i < attr.gid_tbl_len; ++i) + kfree(p->gid_group.attrs[i]); - kfree(p->gid_attr); + kfree(p->gid_group.attrs); err_remove_pma: sysfs_remove_group(&p->kobj, &pma_group); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 6ca0061..e8aad15 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -339,16 +339,17 @@ pci_create_resource_files(struct pci_dev *pdev) if (!pci_resource_len(pdev, i)) continue; - res_attr = kmalloc(sizeof(*res_attr) + 10, GFP_ATOMIC); + /* allocate attribute structure, piggyback attribute name */ + res_attr = kcalloc(1, sizeof(*res_attr) + 10, GFP_ATOMIC); if (res_attr) { - memset(res_attr, 0, sizeof(*res_attr) + 10); + char *res_attr_name = (char *)(res_attr + 1); + pdev->res_attr[i] = res_attr; - /* Allocated above after the res_attr struct */ - res_attr->attr.name = (char *)(res_attr + 1); - sprintf(res_attr->attr.name, "resource%d", i); - res_attr->size = pci_resource_len(pdev, i); + sprintf(res_attr_name, "resource%d", i); + res_attr->attr.name = res_attr_name; res_attr->attr.mode = S_IRUSR | S_IWUSR; res_attr->attr.owner = THIS_MODULE; + res_attr->size = pci_resource_len(pdev, i); res_attr->mmap = pci_mmap_resource; res_attr->private = &pdev->resource[i]; sysfs_create_bin_file(&pdev->dev.kobj, res_attr); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 931b5aa..d9cd2d3 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -16,13 +16,13 @@ struct kobject; struct module; struct attribute { - char * name; + const char * name; struct module * owner; mode_t mode; }; struct attribute_group { - char * name; + const char * name; struct attribute ** attrs; }; -- cgit v0.10.2 From c76d0abd07a9c9cf72bbb5b641e1e97f92ea8f3e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 29 Apr 2005 01:22:00 -0500 Subject: [PATCH] sysfs: if show/store is missing return -EIO sysfs: if attribute does not implement show or store method read/write should return -EIO instead of 0 or -EINVAL. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index d4aaa88..78899ee 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -25,7 +25,7 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) struct kobject * kobj = to_kobj(dentry->d_parent); if (!attr->read) - return -EINVAL; + return -EIO; return attr->read(kobj, buffer, off, count); } @@ -71,7 +71,7 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) struct kobject *kobj = to_kobj(dentry->d_parent); if (!attr->write) - return -EINVAL; + return -EIO; return attr->write(kobj, buffer, offset, count); } diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 3642080..1481cae 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -23,7 +23,7 @@ subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page) { struct subsystem * s = to_subsys(kobj); struct subsys_attribute * sattr = to_sattr(attr); - ssize_t ret = 0; + ssize_t ret = -EIO; if (sattr->show) ret = sattr->show(s,page); @@ -36,7 +36,7 @@ subsys_attr_store(struct kobject * kobj, struct attribute * attr, { struct subsystem * s = to_subsys(kobj); struct subsys_attribute * sattr = to_sattr(attr); - ssize_t ret = 0; + ssize_t ret = -EIO; if (sattr->store) ret = sattr->store(s,page,count); -- cgit v0.10.2 From 4a0c20bf8c0fe2116f8fd7d3da6122bf8a01f026 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 29 Apr 2005 01:23:47 -0500 Subject: [PATCH] sysfs: (driver/base) if show/store is missing return -EIO sysfs: fix drivers/base so if an attribute doesn't implement show or store method read/write will return -EIO instead of 0. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 3cb04bb..80ce88d 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -36,7 +36,7 @@ drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { struct driver_attribute * drv_attr = to_drv_attr(attr); struct device_driver * drv = to_driver(kobj); - ssize_t ret = 0; + ssize_t ret = -EIO; if (drv_attr->show) ret = drv_attr->show(drv, buf); @@ -49,7 +49,7 @@ drv_attr_store(struct kobject * kobj, struct attribute * attr, { struct driver_attribute * drv_attr = to_drv_attr(attr); struct device_driver * drv = to_driver(kobj); - ssize_t ret = 0; + ssize_t ret = -EIO; if (drv_attr->store) ret = drv_attr->store(drv, buf, count); diff --git a/drivers/base/class.c b/drivers/base/class.c index ff33ebb..344b8cd 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -26,7 +26,7 @@ class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { struct class_attribute * class_attr = to_class_attr(attr); struct class * dc = to_class(kobj); - ssize_t ret = 0; + ssize_t ret = -EIO; if (class_attr->show) ret = class_attr->show(dc, buf); @@ -39,7 +39,7 @@ class_attr_store(struct kobject * kobj, struct attribute * attr, { struct class_attribute * class_attr = to_class_attr(attr); struct class * dc = to_class(kobj); - ssize_t ret = 0; + ssize_t ret = -EIO; if (class_attr->store) ret = class_attr->store(dc, buf, count); diff --git a/drivers/base/core.c b/drivers/base/core.c index 32f3f09..a293a78 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -36,7 +36,7 @@ dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { struct device_attribute * dev_attr = to_dev_attr(attr); struct device * dev = to_dev(kobj); - ssize_t ret = 0; + ssize_t ret = -EIO; if (dev_attr->show) ret = dev_attr->show(dev, buf); @@ -49,7 +49,7 @@ dev_attr_store(struct kobject * kobj, struct attribute * attr, { struct device_attribute * dev_attr = to_dev_attr(attr); struct device * dev = to_dev(kobj); - ssize_t ret = 0; + ssize_t ret = -EIO; if (dev_attr->store) ret = dev_attr->store(dev, buf, count); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 9102e37..f37a13d 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -37,7 +37,7 @@ sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer) if (sysdev_attr->show) return sysdev_attr->show(sysdev, buffer); - return 0; + return -EIO; } @@ -50,7 +50,7 @@ sysdev_store(struct kobject * kobj, struct attribute * attr, if (sysdev_attr->store) return sysdev_attr->store(sysdev, buffer, count); - return 0; + return -EIO; } static struct sysfs_ops sysfs_ops = { -- cgit v0.10.2 From fc7e4828995d8c9e4c9597f8a19179e4ab53f73e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 29 Apr 2005 01:26:27 -0500 Subject: [PATCH] sysfs: (driver/pci) if show/store is missing return -EIO sysfs: fix drivers/pci so if an attribute does not implement show or store method read/write will return -EIO instead of 0. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index c802f62..c428290 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -73,7 +73,7 @@ static ssize_t hotplug_slot_attr_show(struct kobject *kobj, { struct hotplug_slot *slot = to_hotplug_slot(kobj); struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr); - return attribute->show ? attribute->show(slot, buf) : 0; + return attribute->show ? attribute->show(slot, buf) : -EIO; } static ssize_t hotplug_slot_attr_store(struct kobject *kobj, @@ -81,7 +81,7 @@ static ssize_t hotplug_slot_attr_store(struct kobject *kobj, { struct hotplug_slot *slot = to_hotplug_slot(kobj); struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr); - return attribute->store ? attribute->store(slot, buf, len) : 0; + return attribute->store ? attribute->store(slot, buf, len) : -EIO; } static struct sysfs_ops hotplug_slot_sysfs_ops = { diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index 3285b82..752e651 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -48,7 +48,7 @@ dlpar_attr_store(struct kobject * kobj, struct attribute * attr, struct dlpar_io_attr *dlpar_attr = container_of(attr, struct dlpar_io_attr, attr); return dlpar_attr->store ? - dlpar_attr->store(dlpar_attr, buf, nbytes) : 0; + dlpar_attr->store(dlpar_attr, buf, nbytes) : -EIO; } static struct sysfs_ops dlpar_attr_sysfs_ops = { diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index cf2cff7..e65bf2b 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -335,13 +335,14 @@ pci_driver_attr_show(struct kobject * kobj, struct attribute *attr, char *buf) { struct device_driver *driver = kobj_to_pci_driver(kobj); struct driver_attribute *dattr = attr_to_driver_attribute(attr); - ssize_t ret = 0; + ssize_t ret; - if (get_driver(driver)) { - if (dattr->show) - ret = dattr->show(driver, buf); - put_driver(driver); - } + if (!get_driver(driver)) + return -ENODEV; + + ret = dattr->show ? dattr->show(driver, buf) : -EIO; + + put_driver(driver); return ret; } @@ -351,13 +352,14 @@ pci_driver_attr_store(struct kobject * kobj, struct attribute *attr, { struct device_driver *driver = kobj_to_pci_driver(kobj); struct driver_attribute *dattr = attr_to_driver_attribute(attr); - ssize_t ret = 0; + ssize_t ret; - if (get_driver(driver)) { - if (dattr->store) - ret = dattr->store(driver, buf, count); - put_driver(driver); - } + if (!get_driver(driver)) + return -ENODEV; + + ret = dattr->store ? dattr->store(driver, buf, count) : -EIO; + + put_driver(driver); return ret; } -- cgit v0.10.2 From 6c1852a08e444a2e66367352a99c0e93c8bf3e97 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 29 Apr 2005 01:26:06 -0500 Subject: [PATCH] sysfs: (driver/block) if show/store is missing return -EIO sysfs: fix drivers/block so if an attribute doesn't implement show or store method read/write will return -EIO instead of 0 or -EINVAL. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c index a9575bb..638db06 100644 --- a/drivers/block/as-iosched.c +++ b/drivers/block/as-iosched.c @@ -2044,7 +2044,7 @@ as_attr_show(struct kobject *kobj, struct attribute *attr, char *page) struct as_fs_entry *entry = to_as(attr); if (!entry->show) - return 0; + return -EIO; return entry->show(e->elevator_data, page); } @@ -2057,7 +2057,7 @@ as_attr_store(struct kobject *kobj, struct attribute *attr, struct as_fs_entry *entry = to_as(attr); if (!entry->store) - return -EINVAL; + return -EIO; return entry->store(e->elevator_data, page, length); } diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index 2210bac..3ac47dd 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -1775,7 +1775,7 @@ cfq_attr_show(struct kobject *kobj, struct attribute *attr, char *page) struct cfq_fs_entry *entry = to_cfq(attr); if (!entry->show) - return 0; + return -EIO; return entry->show(e->elevator_data, page); } @@ -1788,7 +1788,7 @@ cfq_attr_store(struct kobject *kobj, struct attribute *attr, struct cfq_fs_entry *entry = to_cfq(attr); if (!entry->store) - return -EINVAL; + return -EIO; return entry->store(e->elevator_data, page, length); } diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c index d63d34c..7f79f3d 100644 --- a/drivers/block/deadline-iosched.c +++ b/drivers/block/deadline-iosched.c @@ -886,7 +886,7 @@ deadline_attr_show(struct kobject *kobj, struct attribute *attr, char *page) struct deadline_fs_entry *entry = to_deadline(attr); if (!entry->show) - return 0; + return -EIO; return entry->show(e->elevator_data, page); } @@ -899,7 +899,7 @@ deadline_attr_store(struct kobject *kobj, struct attribute *attr, struct deadline_fs_entry *entry = to_deadline(attr); if (!entry->store) - return -EINVAL; + return -EIO; return entry->store(e->elevator_data, page, length); } diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 8bbe01d..53f7d84 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -322,7 +322,7 @@ static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr, struct gendisk *disk = to_disk(kobj); struct disk_attribute *disk_attr = container_of(attr,struct disk_attribute,attr); - ssize_t ret = 0; + ssize_t ret = -EIO; if (disk_attr->show) ret = disk_attr->show(disk,page); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index f20eba2..81fe3a0 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -3574,7 +3574,7 @@ queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page) q = container_of(kobj, struct request_queue, kobj); if (!entry->show) - return 0; + return -EIO; return entry->show(q, page); } @@ -3588,7 +3588,7 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr, q = container_of(kobj, struct request_queue, kobj); if (!entry->store) - return -EINVAL; + return -EIO; return entry->store(q, page, length); } -- cgit v0.10.2 From 70f2817a43c89b784dc2ec3d06ba5bf3064f8235 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 29 Apr 2005 01:27:34 -0500 Subject: [PATCH] sysfs: (rest) if show/store is missing return -EIO sysfs: fix the rest of the kernel so if an attribute doesn't implement show or store method read/write will return -EIO instead of 0 or -EINVAL or -EPERM. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 119c940..e858855 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -65,14 +65,14 @@ static ssize_t acpi_device_attr_show(struct kobject *kobj, { struct acpi_device *device = to_acpi_device(kobj); struct acpi_device_attribute *attribute = to_handle_attr(attr); - return attribute->show ? attribute->show(device, buf) : 0; + return attribute->show ? attribute->show(device, buf) : -EIO; } static ssize_t acpi_device_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len) { struct acpi_device *device = to_acpi_device(kobj); struct acpi_device_attribute *attribute = to_handle_attr(attr); - return attribute->store ? attribute->store(device, buf, len) : len; + return attribute->store ? attribute->store(device, buf, len) : -EIO; } static struct sysfs_ops acpi_device_sysfs_ops = { diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 03b5fb2..bf62dfe 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -521,7 +521,7 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf) policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; - ret = fattr->show ? fattr->show(policy,buf) : 0; + ret = fattr->show ? fattr->show(policy,buf) : -EIO; cpufreq_cpu_put(policy); return ret; } @@ -535,7 +535,7 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr, policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; - ret = fattr->store ? fattr->store(policy,buf,count) : 0; + ret = fattr->store ? fattr->store(policy,buf,count) : -EIO; cpufreq_cpu_put(policy); return ret; } diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 33b669e..6996476 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -115,7 +115,7 @@ edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf) { struct edd_device *dev = to_edd_device(kobj); struct edd_attribute *edd_attr = to_edd_attr(attr); - ssize_t ret = 0; + ssize_t ret = -EIO; if (edd_attr->show) ret = edd_attr->show(dev, buf); diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 0287ff6..a3451cb 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -352,7 +352,7 @@ static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr, { struct efivar_entry *var = to_efivar_entry(kobj); struct efivar_attribute *efivar_attr = to_efivar_attr(attr); - ssize_t ret = 0; + ssize_t ret = -EIO; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -368,7 +368,7 @@ static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr, { struct efivar_entry *var = to_efivar_entry(kobj); struct efivar_attribute *efivar_attr = to_efivar_attr(attr); - ssize_t ret = 0; + ssize_t ret = -EIO; if (!capable(CAP_SYS_ADMIN)) return -EACCES; diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 5febd6d..90d51b1 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -71,7 +71,7 @@ static ssize_t port_attr_show(struct kobject *kobj, struct ib_port *p = container_of(kobj, struct ib_port, kobj); if (!port_attr->show) - return 0; + return -EIO; return port_attr->show(p, port_attr, buf); } diff --git a/kernel/params.c b/kernel/params.c index 5513844..d586c35ef 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -629,7 +629,7 @@ static ssize_t module_attr_show(struct kobject *kobj, mk = to_module_kobject(kobj); if (!attribute->show) - return -EPERM; + return -EIO; if (!try_module_get(mk->mod)) return -ENODEV; @@ -653,7 +653,7 @@ static ssize_t module_attr_store(struct kobject *kobj, mk = to_module_kobject(kobj); if (!attribute->store) - return -EPERM; + return -EIO; if (!try_module_get(mk->mod)) return -ENODEV; diff --git a/security/seclvl.c b/security/seclvl.c index 8a0ab0d..c8e87b2 100644 --- a/security/seclvl.c +++ b/security/seclvl.c @@ -155,7 +155,7 @@ seclvl_attr_store(struct kobject *kobj, struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj); struct seclvl_attribute *attribute = container_of(attr, struct seclvl_attribute, attr); - return (attribute->store ? attribute->store(obj, buf, len) : 0); + return attribute->store ? attribute->store(obj, buf, len) : -EIO; } static ssize_t @@ -164,7 +164,7 @@ seclvl_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj); struct seclvl_attribute *attribute = container_of(attr, struct seclvl_attribute, attr); - return (attribute->show ? attribute->show(obj, buf) : 0); + return attribute->show ? attribute->show(obj, buf) : -EIO; } /** -- cgit v0.10.2 From e9ba6365fd4f0d9e7d022c883bd044fbaa48257f Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Tue, 15 Mar 2005 11:54:21 -0800 Subject: [PATCH] CLASS: move a "simple" class logic into the class core. One step on improving the class api so that it can not be used incorrectly. This also fixes the module owner issue with the dev files that happened when the devt logic moved to the class core. Based on a patch originally written by Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/class.c b/drivers/base/class.c index 344b8cd..a3b006b 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "base.h" #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) @@ -162,6 +163,51 @@ void class_unregister(struct class * cls) subsystem_unregister(&cls->subsys); } +static void class_create_release(struct class *cls) +{ + kfree(cls); +} + +static void class_device_create_release(struct class_device *class_dev) +{ + kfree(class_dev); +} + +struct class *class_create(struct module *owner, char *name) +{ + struct class *cls; + int retval; + + cls = kmalloc(sizeof(struct class), GFP_KERNEL); + if (!cls) { + retval = -ENOMEM; + goto error; + } + memset(cls, 0x00, sizeof(struct class)); + + cls->name = name; + cls->owner = owner; + cls->class_release = class_create_release; + cls->release = class_device_create_release; + + retval = class_register(cls); + if (retval) + goto error; + + return cls; + +error: + kfree(cls); + return ERR_PTR(retval); +} + +void class_destroy(struct class *cls) +{ + if ((cls == NULL) || (IS_ERR(cls))) + return; + + class_unregister(cls); +} /* Class Device Stuff */ @@ -375,7 +421,6 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf) { return print_dev_t(buf, class_dev->devt); } -static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); void class_device_initialize(struct class_device *class_dev) { @@ -412,7 +457,31 @@ int class_device_add(struct class_device *class_dev) if ((error = kobject_add(&class_dev->kobj))) goto register_done; - /* now take care of our own registration */ + /* add the needed attributes to this device */ + if (MAJOR(class_dev->devt)) { + struct class_device_attribute *attr; + attr = kmalloc(sizeof(*attr), GFP_KERNEL); + if (!attr) { + error = -ENOMEM; + kobject_del(&class_dev->kobj); + goto register_done; + } + memset(attr, sizeof(*attr), 0x00); + attr->attr.name = "dev"; + attr->attr.mode = S_IRUGO; + attr->attr.owner = parent->owner; + attr->show = show_dev; + attr->store = NULL; + class_device_create_file(class_dev, attr); + class_dev->devt_attr = attr; + } + + class_device_add_attrs(class_dev); + if (class_dev->dev) + sysfs_create_link(&class_dev->kobj, + &class_dev->dev->kobj, "device"); + + /* notify any interfaces this device is now here */ if (parent) { down(&parent->sem); list_add_tail(&class_dev->node, &parent->children); @@ -421,16 +490,8 @@ int class_device_add(struct class_device *class_dev) class_intf->add(class_dev); up(&parent->sem); } - - if (MAJOR(class_dev->devt)) - class_device_create_file(class_dev, &class_device_attr_dev); - - class_device_add_attrs(class_dev); - if (class_dev->dev) - sysfs_create_link(&class_dev->kobj, - &class_dev->dev->kobj, "device"); - kobject_hotplug(&class_dev->kobj, KOBJ_ADD); + register_done: if (error && parent) class_put(parent); @@ -444,6 +505,41 @@ int class_device_register(struct class_device *class_dev) return class_device_add(class_dev); } +struct class_device *class_device_create(struct class *cls, dev_t devt, + struct device *device, char *fmt, ...) +{ + va_list args; + struct class_device *class_dev = NULL; + int retval = -ENODEV; + + if (cls == NULL || IS_ERR(cls)) + goto error; + + class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL); + if (!class_dev) { + retval = -ENOMEM; + goto error; + } + memset(class_dev, 0x00, sizeof(struct class_device)); + + class_dev->devt = devt; + class_dev->dev = device; + class_dev->class = cls; + + va_start(args, fmt); + vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args); + va_end(args); + retval = class_device_register(class_dev); + if (retval) + goto error; + + return class_dev; + +error: + kfree(class_dev); + return ERR_PTR(retval); +} + void class_device_del(struct class_device *class_dev) { struct class * parent = class_dev->class; @@ -460,6 +556,11 @@ void class_device_del(struct class_device *class_dev) if (class_dev->dev) sysfs_remove_link(&class_dev->kobj, "device"); + if (class_dev->devt_attr) { + class_device_remove_file(class_dev, class_dev->devt_attr); + kfree(class_dev->devt_attr); + class_dev->devt_attr = NULL; + } class_device_remove_attrs(class_dev); kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE); @@ -477,6 +578,24 @@ void class_device_unregister(struct class_device *class_dev) class_device_put(class_dev); } +void class_device_destroy(struct class *cls, dev_t devt) +{ + struct class_device *class_dev = NULL; + struct class_device *class_dev_tmp; + + down(&cls->sem); + list_for_each_entry(class_dev_tmp, &cls->children, node) { + if (class_dev_tmp->devt == devt) { + class_dev = class_dev_tmp; + break; + } + } + up(&cls->sem); + + if (class_dev) + class_device_unregister(class_dev); +} + int class_device_rename(struct class_device *class_dev, char *new_name) { int error = 0; @@ -576,6 +695,8 @@ EXPORT_SYMBOL_GPL(class_register); EXPORT_SYMBOL_GPL(class_unregister); EXPORT_SYMBOL_GPL(class_get); EXPORT_SYMBOL_GPL(class_put); +EXPORT_SYMBOL_GPL(class_create); +EXPORT_SYMBOL_GPL(class_destroy); EXPORT_SYMBOL_GPL(class_device_register); EXPORT_SYMBOL_GPL(class_device_unregister); @@ -584,6 +705,8 @@ EXPORT_SYMBOL_GPL(class_device_add); EXPORT_SYMBOL_GPL(class_device_del); EXPORT_SYMBOL_GPL(class_device_get); EXPORT_SYMBOL_GPL(class_device_put); +EXPORT_SYMBOL_GPL(class_device_create); +EXPORT_SYMBOL_GPL(class_device_destroy); EXPORT_SYMBOL_GPL(class_device_create_file); EXPORT_SYMBOL_GPL(class_device_remove_file); EXPORT_SYMBOL_GPL(class_device_create_bin_file); diff --git a/include/linux/device.h b/include/linux/device.h index fa9e6ca..73250d0 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -143,6 +143,7 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute * */ struct class { const char * name; + struct module * owner; struct subsystem subsys; struct list_head children; @@ -185,6 +186,7 @@ struct class_device { struct kobject kobj; struct class * class; /* required */ dev_t devt; /* dev_t, creates the sysfs "dev" */ + struct class_device_attribute *devt_attr; struct device * dev; /* not necessary, but nice to have */ void * class_data; /* class-specific data */ @@ -245,6 +247,13 @@ struct class_interface { extern int class_interface_register(struct class_interface *); extern void class_interface_unregister(struct class_interface *); +extern struct class *class_create(struct module *owner, char *name); +extern void class_destroy(struct class *cls); +extern struct class_device *class_device_create(struct class *cls, dev_t devt, + struct device *device, char *fmt, ...) + __attribute__((format(printf,4,5))); +extern void class_device_destroy(struct class *cls, dev_t devt); + /* interface for class simple stuff */ extern struct class_simple *class_simple_create(struct module *owner, char *name); extern void class_simple_destroy(struct class_simple *cs); -- cgit v0.10.2 From 7fe845d11ad1b4aac098d40c55275569e143c483 Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Tue, 15 Mar 2005 14:23:15 -0800 Subject: [PATCH] tty: move to use the new class code, instead of class_simple Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 26e5e19..3183103 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2654,7 +2654,7 @@ static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) tty->driver->write(tty, &ch, 1); } -static struct class_simple *tty_class; +static struct class *tty_class; /** * tty_register_device - register a tty device @@ -2687,7 +2687,7 @@ void tty_register_device(struct tty_driver *driver, unsigned index, pty_line_name(driver, index, name); else tty_line_name(driver, index, name); - class_simple_device_add(tty_class, dev, device, name); + class_device_create(tty_class, dev, device, name); } /** @@ -2701,7 +2701,7 @@ void tty_register_device(struct tty_driver *driver, unsigned index, void tty_unregister_device(struct tty_driver *driver, unsigned index) { devfs_remove("%s%d", driver->devfs_name, index + driver->name_base); - class_simple_device_remove(MKDEV(driver->major, driver->minor_start) + index); + class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); } EXPORT_SYMBOL(tty_register_device); @@ -2918,7 +2918,7 @@ extern int vty_init(void); static int __init tty_class_init(void) { - tty_class = class_simple_create(THIS_MODULE, "tty"); + tty_class = class_create(THIS_MODULE, "tty"); if (IS_ERR(tty_class)) return PTR_ERR(tty_class); return 0; @@ -2947,14 +2947,14 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); - class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); + class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); - class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); + class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); #ifdef CONFIG_UNIX98_PTYS cdev_init(&ptmx_cdev, &ptmx_fops); @@ -2962,7 +2962,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); - class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); + class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); #endif #ifdef CONFIG_VT @@ -2971,7 +2971,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); - class_simple_device_add(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + class_device_create(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); vty_init(); #endif -- cgit v0.10.2 From 1235686f6e67cf30c460eb77d90a6cb4be57b92f Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Tue, 15 Mar 2005 14:26:30 -0800 Subject: [PATCH] INPUT: move to use the new class code, instead of class_simple Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 17552a2..556264b 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -431,9 +431,9 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor); - class_simple_device_add(input_class, - MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), - dev->dev, "event%d", minor); + class_device_create(input_class, + MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), + dev->dev, "event%d", minor); return &evdev->handle; } @@ -443,7 +443,8 @@ static void evdev_disconnect(struct input_handle *handle) struct evdev *evdev = handle->private; struct evdev_list *list; - class_simple_device_remove(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); + class_device_destroy(input_class, + MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); devfs_remove("input/event%d", evdev->minor); evdev->exist = 0; diff --git a/drivers/input/input.c b/drivers/input/input.c index 3385dd0..83c77c9 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -702,13 +702,13 @@ static int __init input_proc_init(void) static inline int input_proc_init(void) { return 0; } #endif -struct class_simple *input_class; +struct class *input_class; static int __init input_init(void) { int retval = -ENOMEM; - input_class = class_simple_create(THIS_MODULE, "input"); + input_class = class_create(THIS_MODULE, "input"); if (IS_ERR(input_class)) return PTR_ERR(input_class); input_proc_init(); @@ -718,7 +718,7 @@ static int __init input_init(void) remove_proc_entry("devices", proc_bus_input_dir); remove_proc_entry("handlers", proc_bus_input_dir); remove_proc_entry("input", proc_bus); - class_simple_destroy(input_class); + class_destroy(input_class); return retval; } @@ -728,7 +728,7 @@ static int __init input_init(void) remove_proc_entry("handlers", proc_bus_input_dir); remove_proc_entry("input", proc_bus); unregister_chrdev(INPUT_MAJOR, "input"); - class_simple_destroy(input_class); + class_destroy(input_class); } return retval; } @@ -741,7 +741,7 @@ static void __exit input_exit(void) devfs_remove("input"); unregister_chrdev(INPUT_MAJOR, "input"); - class_simple_destroy(input_class); + class_destroy(input_class); } subsys_initcall(input_init); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 627d343..39775fc 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -452,9 +452,9 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/js%d", minor); - class_simple_device_add(input_class, - MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), - dev->dev, "js%d", minor); + class_device_create(input_class, + MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), + dev->dev, "js%d", minor); return &joydev->handle; } @@ -464,7 +464,7 @@ static void joydev_disconnect(struct input_handle *handle) struct joydev *joydev = handle->private; struct joydev_list *list; - class_simple_device_remove(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); + class_device_destroy(input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); devfs_remove("input/js%d", joydev->minor); joydev->exist = 0; diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 96fb987..062848a 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -647,9 +647,9 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor); - class_simple_device_add(input_class, - MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), - dev->dev, "mouse%d", minor); + class_device_create(input_class, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), + dev->dev, "mouse%d", minor); return &mousedev->handle; } @@ -659,7 +659,8 @@ static void mousedev_disconnect(struct input_handle *handle) struct mousedev *mousedev = handle->private; struct mousedev_list *list; - class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); + class_device_destroy(input_class, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); devfs_remove("input/mouse%d", mousedev->minor); mousedev->exist = 0; @@ -735,8 +736,8 @@ static int __init mousedev_init(void) devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), S_IFCHR|S_IRUGO|S_IWUSR, "input/mice"); - class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), - NULL, "mice"); + class_device_create(input_class, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX if (!(psaux_registered = !misc_register(&psaux_mouse))) @@ -755,7 +756,8 @@ static void __exit mousedev_exit(void) misc_deregister(&psaux_mouse); #endif devfs_remove("input/mice"); - class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); + class_device_destroy(input_class, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); input_unregister_handler(&mousedev_handler); } diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index d0afba8..50c63a1 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -414,9 +414,9 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2), S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor); - class_simple_device_add(input_class, - MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), - dev->dev, "ts%d", minor); + class_device_create(input_class, + MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), + dev->dev, "ts%d", minor); return &tsdev->handle; } @@ -426,7 +426,8 @@ static void tsdev_disconnect(struct input_handle *handle) struct tsdev *tsdev = handle->private; struct tsdev_list *list; - class_simple_device_remove(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); + class_device_destroy(input_class, + MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); devfs_remove("input/ts%d", tsdev->minor); devfs_remove("input/tsraw%d", tsdev->minor); tsdev->exist = 0; diff --git a/include/linux/input.h b/include/linux/input.h index 72731d7..9d9598e 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1015,7 +1015,7 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min dev->absbit[LONG(axis)] |= BIT(axis); } -extern struct class_simple *input_class; +extern struct class *input_class; #endif #endif -- cgit v0.10.2 From 8561b10f6e7ef0a085709ffc844f74130a067abe Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Tue, 15 Mar 2005 15:10:13 -0800 Subject: [PATCH] USB: move the usb hcd code to use the new class code. This moves a kref into the main hcd structure, which detaches it from the class device structure. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 266e9e0..d041782 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -651,50 +651,45 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) /*-------------------------------------------------------------------------*/ /* exported only within usbcore */ -struct usb_bus *usb_bus_get (struct usb_bus *bus) +struct usb_bus *usb_bus_get(struct usb_bus *bus) { - struct class_device *tmp; + if (bus) + kref_get(&bus->kref); + return bus; +} - if (!bus) - return NULL; +static void usb_host_release(struct kref *kref) +{ + struct usb_bus *bus = container_of(kref, struct usb_bus, kref); - tmp = class_device_get(&bus->class_dev); - if (tmp) - return to_usb_bus(tmp); - else - return NULL; + if (bus->release) + bus->release(bus); } /* exported only within usbcore */ -void usb_bus_put (struct usb_bus *bus) +void usb_bus_put(struct usb_bus *bus) { if (bus) - class_device_put(&bus->class_dev); + kref_put(&bus->kref, usb_host_release); } /*-------------------------------------------------------------------------*/ -static void usb_host_release(struct class_device *class_dev) -{ - struct usb_bus *bus = to_usb_bus(class_dev); - - if (bus->release) - bus->release(bus); -} - -static struct class usb_host_class = { - .name = "usb_host", - .release = &usb_host_release, -}; +static struct class *usb_host_class; int usb_host_init(void) { - return class_register(&usb_host_class); + int retval = 0; + + usb_host_class = class_create(THIS_MODULE, "usb_host"); + if (IS_ERR(usb_host_class)) + retval = PTR_ERR(usb_host_class); + return retval; } void usb_host_cleanup(void) { - class_unregister(&usb_host_class); + class_destroy(usb_host_class); } /** @@ -719,8 +714,7 @@ static void usb_bus_init (struct usb_bus *bus) INIT_LIST_HEAD (&bus->bus_list); - class_device_initialize(&bus->class_dev); - bus->class_dev.class = &usb_host_class; + kref_init(&bus->kref); } /** @@ -761,7 +755,6 @@ struct usb_bus *usb_alloc_bus (struct usb_operations *op) static int usb_register_bus(struct usb_bus *bus) { int busnum; - int retval; down (&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); @@ -774,15 +767,15 @@ static int usb_register_bus(struct usb_bus *bus) return -E2BIG; } - snprintf(bus->class_dev.class_id, BUS_ID_SIZE, "usb%d", busnum); - bus->class_dev.dev = bus->controller; - retval = class_device_add(&bus->class_dev); - if (retval) { + bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb%d", busnum); + if (IS_ERR(bus->class_dev)) { clear_bit(busnum, busmap.busmap); up(&usb_bus_list_lock); - return retval; + return PTR_ERR(bus->class_dev); } + class_set_devdata(bus->class_dev, bus); + /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); up (&usb_bus_list_lock); @@ -820,7 +813,7 @@ static void usb_deregister_bus (struct usb_bus *bus) clear_bit (bus->busnum, busmap.busmap); - class_device_del(&bus->class_dev); + class_device_unregister(bus->class_dev); } /** diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 9b347d7..2ff11d5 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -450,7 +450,7 @@ show_async (struct class_device *class_dev, char *buf) *buf = 0; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ehci = hcd_to_ehci (hcd); next = buf; @@ -496,7 +496,7 @@ show_periodic (struct class_device *class_dev, char *buf) return 0; seen_count = 0; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ehci = hcd_to_ehci (hcd); next = buf; @@ -633,7 +633,7 @@ show_registers (struct class_device *class_dev, char *buf) static char fmt [] = "%*s\n"; static char label [] = ""; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ehci = hcd_to_ehci (hcd); next = buf; @@ -735,7 +735,7 @@ static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); static inline void create_debug_files (struct ehci_hcd *ehci) { - struct class_device *cldev = &ehci_to_hcd(ehci)->self.class_dev; + struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev; class_device_create_file(cldev, &class_device_attr_async); class_device_create_file(cldev, &class_device_attr_periodic); @@ -744,7 +744,7 @@ static inline void create_debug_files (struct ehci_hcd *ehci) static inline void remove_debug_files (struct ehci_hcd *ehci) { - struct class_device *cldev = &ehci_to_hcd(ehci)->self.class_dev; + struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev; class_device_remove_file(cldev, &class_device_attr_async); class_device_remove_file(cldev, &class_device_attr_periodic); diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 62f53a2..c58408c 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -481,7 +481,7 @@ show_async (struct class_device *class_dev, char *buf) size_t temp; unsigned long flags; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ohci = hcd_to_ohci(hcd); @@ -514,7 +514,7 @@ show_periodic (struct class_device *class_dev, char *buf) return 0; seen_count = 0; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ohci = hcd_to_ohci(hcd); next = buf; @@ -611,7 +611,7 @@ show_registers (struct class_device *class_dev, char *buf) char *next; u32 rdata; - bus = to_usb_bus(class_dev); + bus = class_get_devdata(class_dev); hcd = bus->hcpriv; ohci = hcd_to_ohci(hcd); regs = ohci->regs; @@ -684,7 +684,7 @@ static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); static inline void create_debug_files (struct ohci_hcd *ohci) { - struct class_device *cldev = &ohci_to_hcd(ohci)->self.class_dev; + struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; class_device_create_file(cldev, &class_device_attr_async); class_device_create_file(cldev, &class_device_attr_periodic); @@ -694,7 +694,7 @@ static inline void create_debug_files (struct ohci_hcd *ohci) static inline void remove_debug_files (struct ohci_hcd *ohci) { - struct class_device *cldev = &ohci_to_hcd(ohci)->self.class_dev; + struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev; class_device_remove_file(cldev, &class_device_attr_async); class_device_remove_file(cldev, &class_device_attr_periodic); diff --git a/include/linux/usb.h b/include/linux/usb.h index 2d1ac50..3d508bf 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -287,15 +287,14 @@ struct usb_bus { struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ - struct class_device class_dev; /* class device for this bus */ + struct class_device *class_dev; /* class device for this bus */ + struct kref kref; /* handles reference counting this bus */ void (*release)(struct usb_bus *bus); /* function to destroy this bus's memory */ #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) struct mon_bus *mon_bus; /* non-null when associated */ int monitored; /* non-zero when monitored */ #endif }; -#define to_usb_bus(d) container_of(d, struct usb_bus, class_dev) - /* -------------------------------------------------------------------------- */ -- cgit v0.10.2 From 619e666b7e9d2b0545ab60a9c824ae5f77c20c3b Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 09:51:41 -0800 Subject: [PATCH] class: convert sound/* to use the new class api instead of class_simple Signed-off-by: Greg Kroah-Hartman diff --git a/sound/core/sound.c b/sound/core/sound.c index 88e0520..33eaa5e 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -64,7 +64,7 @@ static struct list_head snd_minors_hash[SNDRV_CARDS]; static DECLARE_MUTEX(sound_mutex); -extern struct class_simple *sound_class; +extern struct class *sound_class; #ifdef CONFIG_KMOD @@ -231,7 +231,7 @@ int snd_register_device(int type, snd_card_t * card, int dev, snd_minor_t * reg, devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name); if (card) device = card->dev; - class_simple_device_add(sound_class, MKDEV(major, minor), device, name); + class_device_create(sound_class, MKDEV(major, minor), device, "%s", name); up(&sound_mutex); return 0; @@ -263,7 +263,7 @@ int snd_unregister_device(int type, snd_card_t * card, int dev) if (strncmp(mptr->name, "controlC", 8) || card->number >= cards_limit) /* created in sound.c */ devfs_remove("snd/%s", mptr->name); - class_simple_device_remove(MKDEV(major, minor)); + class_device_destroy(sound_class, MKDEV(major, minor)); list_del(&mptr->list); up(&sound_mutex); diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index de91c90..a686be9 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -73,7 +73,7 @@ static char dma_alloc_map[MAX_DMA_CHANNELS]; unsigned long seq_time = 0; /* Time for /dev/sequencer */ -extern struct class_simple *sound_class; +extern struct class *sound_class; /* * Table for configurable mixer volume handling @@ -567,9 +567,9 @@ static int __init oss_init(void) devfs_mk_cdev(MKDEV(SOUND_MAJOR, dev_list[i].minor), S_IFCHR | dev_list[i].mode, "sound/%s", dev_list[i].name); - class_simple_device_add(sound_class, - MKDEV(SOUND_MAJOR, dev_list[i].minor), - NULL, "%s", dev_list[i].name); + class_device_create(sound_class, + MKDEV(SOUND_MAJOR, dev_list[i].minor), + NULL, "%s", dev_list[i].name); if (!dev_list[i].num) continue; @@ -579,10 +579,9 @@ static int __init oss_init(void) dev_list[i].minor + (j*0x10)), S_IFCHR | dev_list[i].mode, "sound/%s%d", dev_list[i].name, j); - class_simple_device_add(sound_class, - MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)), - NULL, - "%s%d", dev_list[i].name, j); + class_device_create(sound_class, + MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)), + NULL, "%s%d", dev_list[i].name, j); } } @@ -598,12 +597,12 @@ static void __exit oss_cleanup(void) for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) { devfs_remove("sound/%s", dev_list[i].name); - class_simple_device_remove(MKDEV(SOUND_MAJOR, dev_list[i].minor)); + class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor)); if (!dev_list[i].num) continue; for (j = 1; j < *dev_list[i].num; j++) { devfs_remove("sound/%s%d", dev_list[i].name, j); - class_simple_device_remove(MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10))); + class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10))); } } diff --git a/sound/sound_core.c b/sound/sound_core.c index 30f75c9..21a69e0 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -65,7 +65,7 @@ extern int msnd_classic_init(void); extern int msnd_pinnacle_init(void); #endif -struct class_simple *sound_class; +struct class *sound_class; EXPORT_SYMBOL(sound_class); /* @@ -174,7 +174,7 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor), S_IFCHR | mode, s->name); - class_simple_device_add(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor), + class_device_create(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor), NULL, s->name+6); return r; @@ -198,7 +198,7 @@ static void sound_remove_unit(struct sound_unit **list, int unit) spin_unlock(&sound_loader_lock); if (p) { devfs_remove(p->name); - class_simple_device_remove(MKDEV(SOUND_MAJOR, p->unit_minor)); + class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor)); kfree(p); } } @@ -562,7 +562,7 @@ static void __exit cleanup_soundcore(void) empty */ unregister_chrdev(SOUND_MAJOR, "sound"); devfs_remove("sound"); - class_simple_destroy(sound_class); + class_destroy(sound_class); } static int __init init_soundcore(void) @@ -572,7 +572,7 @@ static int __init init_soundcore(void) return -EBUSY; } devfs_mk_dir ("sound"); - sound_class = class_simple_create(THIS_MODULE, "sound"); + sound_class = class_create(THIS_MODULE, "sound"); if (IS_ERR(sound_class)) return PTR_ERR(sound_class); -- cgit v0.10.2 From deb3697037a7d362d13468a73643e09cbc1615a8 Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 09:52:10 -0800 Subject: [PATCH] class: convert drivers/block/* to use the new class api instead of class_simple Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 14aeca3..45a2430 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -36,7 +36,7 @@ static int emsgs_head_idx, emsgs_tail_idx; static struct semaphore emsgs_sema; static spinlock_t emsgs_lock; static int nblocked_emsgs_readers; -static struct class_simple *aoe_class; +static struct class *aoe_class; static struct aoe_chardev chardevs[] = { { MINOR_ERR, "err" }, { MINOR_DISCOVER, "discover" }, @@ -218,13 +218,13 @@ aoechr_init(void) } sema_init(&emsgs_sema, 0); spin_lock_init(&emsgs_lock); - aoe_class = class_simple_create(THIS_MODULE, "aoe"); + aoe_class = class_create(THIS_MODULE, "aoe"); if (IS_ERR(aoe_class)) { unregister_chrdev(AOE_MAJOR, "aoechr"); return PTR_ERR(aoe_class); } for (i = 0; i < ARRAY_SIZE(chardevs); ++i) - class_simple_device_add(aoe_class, + class_device_create(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor), NULL, chardevs[i].name); @@ -237,8 +237,8 @@ aoechr_exit(void) int i; for (i = 0; i < ARRAY_SIZE(chardevs); ++i) - class_simple_device_remove(MKDEV(AOE_MAJOR, chardevs[i].minor)); - class_simple_destroy(aoe_class); + class_device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor)); + class_destroy(aoe_class); unregister_chrdev(AOE_MAJOR, "aoechr"); } diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index dbeb107..84d8e29 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -222,7 +222,7 @@ static int pg_identify(struct pg *dev, int log); static char pg_scratch[512]; /* scratch block buffer */ -static struct class_simple *pg_class; +static struct class *pg_class; /* kernel glue structures */ @@ -666,7 +666,7 @@ static int __init pg_init(void) err = -1; goto out; } - pg_class = class_simple_create(THIS_MODULE, "pg"); + pg_class = class_create(THIS_MODULE, "pg"); if (IS_ERR(pg_class)) { err = PTR_ERR(pg_class); goto out_chrdev; @@ -675,7 +675,7 @@ static int __init pg_init(void) for (unit = 0; unit < PG_UNITS; unit++) { struct pg *dev = &devices[unit]; if (dev->present) { - class_simple_device_add(pg_class, MKDEV(major, unit), + class_device_create(pg_class, MKDEV(major, unit), NULL, "pg%u", unit); err = devfs_mk_cdev(MKDEV(major, unit), S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u", @@ -688,8 +688,8 @@ static int __init pg_init(void) goto out; out_class: - class_simple_device_remove(MKDEV(major, unit)); - class_simple_destroy(pg_class); + class_device_destroy(pg_class, MKDEV(major, unit)); + class_destroy(pg_class); out_chrdev: unregister_chrdev(major, "pg"); out: @@ -703,11 +703,11 @@ static void __exit pg_exit(void) for (unit = 0; unit < PG_UNITS; unit++) { struct pg *dev = &devices[unit]; if (dev->present) { - class_simple_device_remove(MKDEV(major, unit)); + class_device_destroy(pg_class, MKDEV(major, unit)); devfs_remove("pg/%u", unit); } } - class_simple_destroy(pg_class); + class_destroy(pg_class); devfs_remove("pg"); unregister_chrdev(major, name); diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index 8fbd692..5fe8ee8 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -242,7 +242,7 @@ static struct file_operations pt_fops = { }; /* sysfs class support */ -static struct class_simple *pt_class; +static struct class *pt_class; static inline int status_reg(struct pi_adapter *pi) { @@ -963,7 +963,7 @@ static int __init pt_init(void) err = -1; goto out; } - pt_class = class_simple_create(THIS_MODULE, "pt"); + pt_class = class_create(THIS_MODULE, "pt"); if (IS_ERR(pt_class)) { err = PTR_ERR(pt_class); goto out_chrdev; @@ -972,29 +972,29 @@ static int __init pt_init(void) devfs_mk_dir("pt"); for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { - class_simple_device_add(pt_class, MKDEV(major, unit), + class_device_create(pt_class, MKDEV(major, unit), NULL, "pt%d", unit); err = devfs_mk_cdev(MKDEV(major, unit), S_IFCHR | S_IRUSR | S_IWUSR, "pt/%d", unit); if (err) { - class_simple_device_remove(MKDEV(major, unit)); + class_device_destroy(pt_class, MKDEV(major, unit)); goto out_class; } - class_simple_device_add(pt_class, MKDEV(major, unit + 128), + class_device_create(pt_class, MKDEV(major, unit + 128), NULL, "pt%dn", unit); err = devfs_mk_cdev(MKDEV(major, unit + 128), S_IFCHR | S_IRUSR | S_IWUSR, "pt/%dn", unit); if (err) { - class_simple_device_remove(MKDEV(major, unit + 128)); + class_device_destroy(pt_class, MKDEV(major, unit + 128)); goto out_class; } } goto out; out_class: - class_simple_destroy(pt_class); + class_destroy(pt_class); out_chrdev: unregister_chrdev(major, "pt"); out: @@ -1006,12 +1006,12 @@ static void __exit pt_exit(void) int unit; for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { - class_simple_device_remove(MKDEV(major, unit)); + class_device_destroy(pt_class, MKDEV(major, unit)); devfs_remove("pt/%d", unit); - class_simple_device_remove(MKDEV(major, unit + 128)); + class_device_destroy(pt_class, MKDEV(major, unit + 128)); devfs_remove("pt/%dn", unit); } - class_simple_destroy(pt_class); + class_destroy(pt_class); devfs_remove("pt"); unregister_chrdev(major, name); for (unit = 0; unit < PT_UNITS; unit++) -- cgit v0.10.2 From ca8eca6884861c1ce294b05aacfdf9045bba9aff Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 09:53:09 -0800 Subject: [PATCH] class: convert drivers/char/* to use the new class api instead of class_simple Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 37d6649..26271e3 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -144,7 +144,7 @@ static struct dsp56k_device { int tx_wsize, rx_wsize; } dsp56k; -static struct class_simple *dsp56k_class; +static struct class *dsp56k_class; static int dsp56k_reset(void) { @@ -510,12 +510,12 @@ static int __init dsp56k_init_driver(void) printk("DSP56k driver: Unable to register driver\n"); return -ENODEV; } - dsp56k_class = class_simple_create(THIS_MODULE, "dsp56k"); + dsp56k_class = class_create(THIS_MODULE, "dsp56k"); if (IS_ERR(dsp56k_class)) { err = PTR_ERR(dsp56k_class); goto out_chrdev; } - class_simple_device_add(dsp56k_class, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); + class_device_create(dsp56k_class, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); err = devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k"); @@ -526,8 +526,8 @@ static int __init dsp56k_init_driver(void) goto out; out_class: - class_simple_device_remove(MKDEV(DSP56K_MAJOR, 0)); - class_simple_destroy(dsp56k_class); + class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); + class_destroy(dsp56k_class); out_chrdev: unregister_chrdev(DSP56K_MAJOR, "dsp56k"); out: @@ -537,8 +537,8 @@ module_init(dsp56k_init_driver); static void __exit dsp56k_cleanup_driver(void) { - class_simple_device_remove(MKDEV(DSP56K_MAJOR, 0)); - class_simple_destroy(dsp56k_class); + class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); + class_destroy(dsp56k_class); unregister_chrdev(DSP56K_MAJOR, "dsp56k"); devfs_remove("dsp56k"); } diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c index dbac7e5..5745b74 100644 --- a/drivers/char/ftape/zftape/zftape-init.c +++ b/drivers/char/ftape/zftape/zftape-init.c @@ -99,7 +99,7 @@ static struct file_operations zft_cdev = .release = zft_close, }; -static struct class_simple *zft_class; +static struct class *zft_class; /* Open floppy tape device */ @@ -329,29 +329,29 @@ KERN_INFO "installing zftape VFS interface for ftape driver ..."); TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); - zft_class = class_simple_create(THIS_MODULE, "zft"); + zft_class = class_create(THIS_MODULE, "zft"); for (i = 0; i < 4; i++) { - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "qft%i", i); - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4), S_IFCHR | S_IRUSR | S_IWUSR, "nqft%i", i); - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16), S_IFCHR | S_IRUSR | S_IWUSR, "zqft%i", i); - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20), S_IFCHR | S_IRUSR | S_IWUSR, "nzqft%i", i); - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32), S_IFCHR | S_IRUSR | S_IWUSR, "rawqft%i", i); - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36), S_IFCHR | S_IRUSR | S_IWUSR, "nrawqft%i", i); @@ -381,19 +381,19 @@ static void zft_exit(void) } for (i = 0; i < 4; i++) { devfs_remove("qft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i)); devfs_remove("nqft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 4)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4)); devfs_remove("zqft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 16)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16)); devfs_remove("nzqft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 20)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20)); devfs_remove("rawqft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 32)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32)); devfs_remove("nrawqft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 36)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36)); } - class_simple_destroy(zft_class); + class_destroy(zft_class); zft_uninit_mem(); /* release remaining memory, if any */ printk(KERN_INFO "zftape successfully unloaded.\n"); TRACE_EXIT; diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index fca9a97..3b8314b 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -302,7 +302,7 @@ static char rirqs[IP2_MAX_BOARDS]; static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0}; /* for sysfs class support */ -static struct class_simple *ip2_class; +static struct class *ip2_class; // Some functions to keep track of what irq's we have @@ -414,9 +414,9 @@ cleanup_module(void) iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); - class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 4 * i)); + class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); devfs_remove("ip2/ipl%d", i); - class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); + class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); devfs_remove("ip2/stat%d", i); } /* Disable and remove interrupt handler. */ @@ -425,7 +425,7 @@ cleanup_module(void) clear_requested_irq( ip2config.irq[i]); } } - class_simple_destroy(ip2_class); + class_destroy(ip2_class); devfs_remove("ip2"); if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) { printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); @@ -700,7 +700,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err ); } else { /* create the sysfs class */ - ip2_class = class_simple_create(THIS_MODULE, "ip2"); + ip2_class = class_create(THIS_MODULE, "ip2"); if (IS_ERR(ip2_class)) { err = PTR_ERR(ip2_class); goto out_chrdev; @@ -722,25 +722,25 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - class_simple_device_add(ip2_class, MKDEV(IP2_IPL_MAJOR, + class_device_create(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i), NULL, "ipl%d", i); err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, "ip2/ipl%d", i); if (err) { - class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, - 4 * i)); + class_device_destroy(ip2_class, + MKDEV(IP2_IPL_MAJOR, 4 * i)); goto out_class; } - class_simple_device_add(ip2_class, MKDEV(IP2_IPL_MAJOR, + class_device_create(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1), NULL, "stat%d", i); err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, "ip2/stat%d", i); if (err) { - class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, - 4 * i + 1)); + class_device_destroy(ip2_class, + MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); goto out_class; } @@ -798,7 +798,7 @@ retry: goto out; out_class: - class_simple_destroy(ip2_class); + class_destroy(ip2_class); out_chrdev: unregister_chrdev(IP2_IPL_MAJOR, "ip2"); out: diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 21aed0e..c02a21d 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -792,7 +792,7 @@ static int stli_timeron; /*****************************************************************************/ -static struct class_simple *istallion_class; +static struct class *istallion_class; #ifdef MODULE @@ -854,10 +854,10 @@ static void __exit istallion_module_exit(void) put_tty_driver(stli_serial); for (i = 0; i < 4; i++) { devfs_remove("staliomem/%d", i); - class_simple_device_remove(MKDEV(STL_SIOMEMMAJOR, i)); + class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i)); } devfs_remove("staliomem"); - class_simple_destroy(istallion_class); + class_destroy(istallion_class); if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) printk("STALLION: failed to un-register serial memory device, " "errno=%d\n", -i); @@ -5242,12 +5242,12 @@ int __init stli_init(void) "device\n"); devfs_mk_dir("staliomem"); - istallion_class = class_simple_create(THIS_MODULE, "staliomem"); + istallion_class = class_create(THIS_MODULE, "staliomem"); for (i = 0; i < 4; i++) { devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "staliomem/%d", i); - class_simple_device_add(istallion_class, MKDEV(STL_SIOMEMMAJOR, i), + class_device_create(istallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); } diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 4dee945..59eebe5 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -146,7 +146,7 @@ static struct lp_struct lp_table[LP_NO]; static unsigned int lp_count = 0; -static struct class_simple *lp_class; +static struct class *lp_class; #ifdef CONFIG_LP_CONSOLE static struct parport *console_registered; // initially NULL @@ -804,7 +804,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_simple_device_add(lp_class, MKDEV(LP_MAJOR, nr), NULL, + class_device_create(lp_class, MKDEV(LP_MAJOR, nr), NULL, "lp%d", nr); devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO, "printers/%d", nr); @@ -907,7 +907,7 @@ static int __init lp_init (void) } devfs_mk_dir("printers"); - lp_class = class_simple_create(THIS_MODULE, "printer"); + lp_class = class_create(THIS_MODULE, "printer"); if (IS_ERR(lp_class)) { err = PTR_ERR(lp_class); goto out_devfs; @@ -930,7 +930,7 @@ static int __init lp_init (void) return 0; out_class: - class_simple_destroy(lp_class); + class_destroy(lp_class); out_devfs: devfs_remove("printers"); unregister_chrdev(LP_MAJOR, "lp"); @@ -981,10 +981,10 @@ static void lp_cleanup_module (void) continue; parport_unregister_device(lp_table[offset].dev); devfs_remove("printers/%d", offset); - class_simple_device_remove(MKDEV(LP_MAJOR, offset)); + class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); } devfs_remove("printers"); - class_simple_destroy(lp_class); + class_destroy(lp_class); } __setup("lp=", lp_setup); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 947cb3c..257b8ee 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -856,7 +856,7 @@ static const struct { {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops}, }; -static struct class_simple *mem_class; +static struct class *mem_class; static int __init chr_dev_init(void) { @@ -865,10 +865,9 @@ static int __init chr_dev_init(void) if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); - mem_class = class_simple_create(THIS_MODULE, "mem"); + mem_class = class_create(THIS_MODULE, "mem"); for (i = 0; i < ARRAY_SIZE(devlist); i++) { - class_simple_device_add(mem_class, - MKDEV(MEM_MAJOR, devlist[i].minor), + class_device_create(mem_class, MKDEV(MEM_MAJOR, devlist[i].minor), NULL, devlist[i].name); devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor), S_IFCHR | devlist[i].mode, devlist[i].name); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 0937544..3115d31 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -177,10 +177,10 @@ fail: /* * TODO for 2.7: - * - add a struct class_device to struct miscdevice and make all usages of + * - add a struct kref to struct miscdevice and make all usages of * them dynamic. */ -static struct class_simple *misc_class; +static struct class *misc_class; static struct file_operations misc_fops = { .owner = THIS_MODULE, @@ -238,8 +238,8 @@ int misc_register(struct miscdevice * misc) } dev = MKDEV(MISC_MAJOR, misc->minor); - misc->class = class_simple_device_add(misc_class, dev, - misc->dev, misc->name); + misc->class = class_device_create(misc_class, dev, misc->dev, + "%s", misc->name); if (IS_ERR(misc->class)) { err = PTR_ERR(misc->class); goto out; @@ -248,7 +248,7 @@ int misc_register(struct miscdevice * misc) err = devfs_mk_cdev(dev, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, misc->devfs_name); if (err) { - class_simple_device_remove(dev); + class_device_destroy(misc_class, dev); goto out; } @@ -281,7 +281,7 @@ int misc_deregister(struct miscdevice * misc) down(&misc_sem); list_del(&misc->list); - class_simple_device_remove(MKDEV(MISC_MAJOR, misc->minor)); + class_device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); devfs_remove(misc->devfs_name); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); @@ -302,7 +302,7 @@ static int __init misc_init(void) if (ent) ent->proc_fops = &misc_proc_fops; #endif - misc_class = class_simple_create(THIS_MODULE, "misc"); + misc_class = class_create(THIS_MODULE, "misc"); if (IS_ERR(misc_class)) return PTR_ERR(misc_class); #ifdef CONFIG_MVME16x @@ -323,7 +323,7 @@ static int __init misc_init(void) if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", MISC_MAJOR); - class_simple_destroy(misc_class); + class_destroy(misc_class); return -EIO; } return 0; diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 5eda075..0e22880 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -737,7 +737,7 @@ static unsigned int pp_poll (struct file * file, poll_table * wait) return mask; } -static struct class_simple *ppdev_class; +static struct class *ppdev_class; static struct file_operations pp_fops = { .owner = THIS_MODULE, @@ -752,13 +752,13 @@ static struct file_operations pp_fops = { static void pp_attach(struct parport *port) { - class_simple_device_add(ppdev_class, MKDEV(PP_MAJOR, port->number), + class_device_create(ppdev_class, MKDEV(PP_MAJOR, port->number), NULL, "parport%d", port->number); } static void pp_detach(struct parport *port) { - class_simple_device_remove(MKDEV(PP_MAJOR, port->number)); + class_device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number)); } static struct parport_driver pp_driver = { @@ -776,7 +776,7 @@ static int __init ppdev_init (void) PP_MAJOR); return -EIO; } - ppdev_class = class_simple_create(THIS_MODULE, CHRDEV); + ppdev_class = class_create(THIS_MODULE, CHRDEV); if (IS_ERR(ppdev_class)) { err = PTR_ERR(ppdev_class); goto out_chrdev; @@ -798,7 +798,7 @@ out_class: for (i = 0; i < PARPORT_MAX; i++) devfs_remove("parports/%d", i); devfs_remove("parports"); - class_simple_destroy(ppdev_class); + class_destroy(ppdev_class); out_chrdev: unregister_chrdev(PP_MAJOR, CHRDEV); out: @@ -813,7 +813,7 @@ static void __exit ppdev_cleanup (void) devfs_remove("parports/%d", i); parport_unregister_driver(&pp_driver); devfs_remove("parports"); - class_simple_destroy(ppdev_class); + class_destroy(ppdev_class); unregister_chrdev (PP_MAJOR, CHRDEV); } diff --git a/drivers/char/raw.c b/drivers/char/raw.c index ca5f42b..f13e5de 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -27,7 +27,7 @@ struct raw_device_data { int inuse; }; -static struct class_simple *raw_class; +static struct class *raw_class; static struct raw_device_data raw_devices[MAX_RAW_MINORS]; static DECLARE_MUTEX(raw_mutex); static struct file_operations raw_ctl_fops; /* forward declaration */ @@ -127,8 +127,8 @@ raw_ioctl(struct inode *inode, struct file *filp, static void bind_device(struct raw_config_request *rq) { - class_simple_device_remove(MKDEV(RAW_MAJOR, rq->raw_minor)); - class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor), + class_device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor)); + class_device_create(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor), NULL, "raw%d", rq->raw_minor); } @@ -200,8 +200,8 @@ static int raw_ctl_ioctl(struct inode *inode, struct file *filp, if (rq.block_major == 0 && rq.block_minor == 0) { /* unbind */ rawdev->binding = NULL; - class_simple_device_remove(MKDEV(RAW_MAJOR, - rq.raw_minor)); + class_device_destroy(raw_class, + MKDEV(RAW_MAJOR, rq.raw_minor)); } else { rawdev->binding = bdget(dev); if (rawdev->binding == NULL) @@ -300,14 +300,14 @@ static int __init raw_init(void) goto error; } - raw_class = class_simple_create(THIS_MODULE, "raw"); + raw_class = class_create(THIS_MODULE, "raw"); if (IS_ERR(raw_class)) { printk(KERN_ERR "Error creating raw class.\n"); cdev_del(&raw_cdev); unregister_chrdev_region(dev, MAX_RAW_MINORS); goto error; } - class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); + class_device_create(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); devfs_mk_cdev(MKDEV(RAW_MAJOR, 0), S_IFCHR | S_IRUGO | S_IWUGO, @@ -331,8 +331,8 @@ static void __exit raw_exit(void) devfs_remove("raw/raw%d", i); devfs_remove("raw/rawctl"); devfs_remove("raw"); - class_simple_device_remove(MKDEV(RAW_MAJOR, 0)); - class_simple_destroy(raw_class); + class_device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); + class_destroy(raw_class); cdev_del(&raw_cdev); unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS); } diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index e3c0b52..901d6f1 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -357,6 +357,8 @@ static struct file_operations scdrv_fops = { .release = scdrv_release, }; +static struct class *snsc_class; + /* * scdrv_init * @@ -372,7 +374,6 @@ scdrv_init(void) char *devnamep; struct sysctl_data_s *scd; void *salbuf; - struct class_simple *snsc_class; dev_t first_dev, dev; nasid_t event_nasid = ia64_sn_get_console_nasid(); @@ -382,7 +383,7 @@ scdrv_init(void) __FUNCTION__); return -ENODEV; } - snsc_class = class_simple_create(THIS_MODULE, SYSCTL_BASENAME); + snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME); for (cnode = 0; cnode < numionodes; cnode++) { geoid = cnodeid_get_geoid(cnode); @@ -436,7 +437,7 @@ scdrv_init(void) continue; } - class_simple_device_add(snsc_class, dev, NULL, + class__device_create(snsc_class, dev, NULL, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index b8899f5..951545a 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -719,7 +719,7 @@ static struct file_operations stl_fsiomem = { /*****************************************************************************/ -static struct class_simple *stallion_class; +static struct class *stallion_class; /* * Loadable module initialization stuff. @@ -777,13 +777,13 @@ static void __exit stallion_module_exit(void) } for (i = 0; i < 4; i++) { devfs_remove("staliomem/%d", i); - class_simple_device_remove(MKDEV(STL_SIOMEMMAJOR, i)); + class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); } devfs_remove("staliomem"); if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) printk("STALLION: failed to un-register serial memory device, " "errno=%d\n", -i); - class_simple_destroy(stallion_class); + class_destroy(stallion_class); if (stl_tmpwritebuf != (char *) NULL) kfree(stl_tmpwritebuf); @@ -3090,12 +3090,12 @@ static int __init stl_init(void) printk("STALLION: failed to register serial board device\n"); devfs_mk_dir("staliomem"); - stallion_class = class_simple_create(THIS_MODULE, "staliomem"); + stallion_class = class_create(THIS_MODULE, "staliomem"); for (i = 0; i < 4; i++) { devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), S_IFCHR|S_IRUSR|S_IWUSR, "staliomem/%d", i); - class_simple_device_add(stallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); + class_device_create(stallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); } stl_serial->owner = THIS_MODULE; diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 0c5ba9d..659335d 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -90,7 +90,7 @@ static int timeout = TIMAXTIME; /* timeout in tenth of seconds */ static unsigned int tp_count; /* tipar count */ static unsigned long opened; /* opened devices */ -static struct class_simple *tipar_class; +static struct class *tipar_class; /* --- macros for parport access -------------------------------------- */ @@ -436,7 +436,7 @@ tipar_register(int nr, struct parport *port) goto out; } - class_simple_device_add(tipar_class, MKDEV(TIPAR_MAJOR, + class_device_create(tipar_class, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), NULL, "par%d", nr); /* Use devfs, tree: /dev/ticables/par/[0..2] */ err = devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), @@ -458,8 +458,8 @@ tipar_register(int nr, struct parport *port) goto out; out_class: - class_simple_device_remove(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr)); - class_simple_destroy(tipar_class); + class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr)); + class_destroy(tipar_class); out: return err; } @@ -505,7 +505,7 @@ tipar_init_module(void) /* Use devfs with tree: /dev/ticables/par/[0..2] */ devfs_mk_dir("ticables/par"); - tipar_class = class_simple_create(THIS_MODULE, "ticables"); + tipar_class = class_create(THIS_MODULE, "ticables"); if (IS_ERR(tipar_class)) { err = PTR_ERR(tipar_class); goto out_chrdev; @@ -539,10 +539,10 @@ tipar_cleanup_module(void) if (table[i].dev == NULL) continue; parport_unregister_device(table[i].dev); - class_simple_device_remove(MKDEV(TIPAR_MAJOR, i)); + class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); devfs_remove("ticables/par/%d", i); } - class_simple_destroy(tipar_class); + class_destroy(tipar_class); devfs_remove("ticables/par"); pr_info("tipar: module unloaded\n"); diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 7abe405..79c2928 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -474,7 +474,7 @@ static struct file_operations vcs_fops = { .open = vcs_open, }; -static struct class_simple *vc_class; +static struct class *vc_class; void vcs_make_devfs(struct tty_struct *tty) { @@ -484,26 +484,26 @@ void vcs_make_devfs(struct tty_struct *tty) devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a%u", tty->index + 1); - class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1); - class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1); + class_device_create(vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1); + class_device_create(vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1); } void vcs_remove_devfs(struct tty_struct *tty) { devfs_remove("vcc/%u", tty->index + 1); devfs_remove("vcc/a%u", tty->index + 1); - class_simple_device_remove(MKDEV(VCS_MAJOR, tty->index + 1)); - class_simple_device_remove(MKDEV(VCS_MAJOR, tty->index + 129)); + class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); + class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); } int __init vcs_init(void) { if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) panic("unable to get major %d for vcs device", VCS_MAJOR); - vc_class = class_simple_create(THIS_MODULE, "vc"); + vc_class = class_create(THIS_MODULE, "vc"); devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0"); devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0"); - class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); - class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); + class_device_create(vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); + class_device_create(vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); return 0; } diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index aea3cbf..4764b4f 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -237,7 +237,7 @@ static dma_addr_t viotape_unitinfo_token; static struct mtget viomtget[VIOTAPE_MAX_TAPE]; -static struct class_simple *tape_class; +static struct class *tape_class; static struct device *tape_device[VIOTAPE_MAX_TAPE]; @@ -956,9 +956,9 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; - class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL, + class_device_create(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL, "iseries!vt%d", i); - class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80), + class_device_create(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL, "iseries!nvt%d", i); devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "iseries/vt%d", i); @@ -980,8 +980,8 @@ static int viotape_remove(struct vio_dev *vdev) devfs_remove("iseries/nvt%d", i); devfs_remove("iseries/vt%d", i); devfs_unregister_tape(state[i].dev_handle); - class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i | 0x80)); - class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i)); + class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); + class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); return 0; } @@ -1045,7 +1045,7 @@ int __init viotap_init(void) goto clear_handler; } - tape_class = class_simple_create(THIS_MODULE, "tape"); + tape_class = class_create(THIS_MODULE, "tape"); if (IS_ERR(tape_class)) { printk(VIOTAPE_KERN_WARN "Unable to allocat class\n"); ret = PTR_ERR(tape_class); @@ -1070,7 +1070,7 @@ int __init viotap_init(void) return 0; unreg_class: - class_simple_destroy(tape_class); + class_destroy(tape_class); unreg_chrdev: unregister_chrdev(VIOTAPE_MAJOR, "viotape"); clear_handler: @@ -1110,7 +1110,7 @@ static void __exit viotap_exit(void) remove_proc_entry("iSeries/viotape", NULL); vio_unregister_driver(&viotape_driver); - class_simple_destroy(tape_class); + class_destroy(tape_class); ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape"); if (ret < 0) printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n", -- cgit v0.10.2 From 7e25ab9155aef04e83da69545742cf65c9b801ce Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 09:53:36 -0800 Subject: [PATCH] class: convert drivers/ieee1394/* to use the new class api instead of class_simple Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index 68c7a5f..4538b02 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c @@ -2343,8 +2343,8 @@ static void dv1394_remove_host (struct hpsb_host *host) dv1394_un_init(video); } while (video != NULL); - class_simple_device_remove(MKDEV( - IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2))); + class_device_destroy(hpsb_protocol_class, + MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2))); devfs_remove("ieee1394/dv/host%d/NTSC", id); devfs_remove("ieee1394/dv/host%d/PAL", id); devfs_remove("ieee1394/dv/host%d", id); @@ -2361,7 +2361,7 @@ static void dv1394_add_host (struct hpsb_host *host) ohci = (struct ti_ohci *)host->hostdata; - class_simple_device_add(hpsb_protocol_class, MKDEV( + class_device_create(hpsb_protocol_class, MKDEV( IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)), NULL, "dv1394-%d", id); devfs_mk_dir("ieee1394/dv/host%d", id); diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index a294e45..2d9a9b7 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -67,7 +67,7 @@ MODULE_LICENSE("GPL"); /* Some globals used */ const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" }; -struct class_simple *hpsb_protocol_class; +struct class *hpsb_protocol_class; #ifdef CONFIG_IEEE1394_VERBOSEDEBUG static void dump_packet(const char *text, quadlet_t *data, int size) @@ -1121,7 +1121,7 @@ static int __init ieee1394_init(void) if (ret < 0) goto release_all_bus; - hpsb_protocol_class = class_simple_create(THIS_MODULE, "ieee1394_protocol"); + hpsb_protocol_class = class_create(THIS_MODULE, "ieee1394_protocol"); if (IS_ERR(hpsb_protocol_class)) { ret = PTR_ERR(hpsb_protocol_class); goto release_class_host; @@ -1159,7 +1159,7 @@ static int __init ieee1394_init(void) cleanup_csr: cleanup_csr(); release_class_protocol: - class_simple_destroy(hpsb_protocol_class); + class_destroy(hpsb_protocol_class); release_class_host: class_unregister(&hpsb_host_class); release_all_bus: @@ -1189,7 +1189,7 @@ static void __exit ieee1394_cleanup(void) cleanup_csr(); - class_simple_destroy(hpsb_protocol_class); + class_destroy(hpsb_protocol_class); class_unregister(&hpsb_host_class); for (i = 0; fw_bus_attrs[i]; i++) bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]); diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index c4b4408..73bd8ef 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -223,6 +223,7 @@ extern int hpsb_disable_irm; /* Our sysfs bus entry */ extern struct bus_type ieee1394_bus_type; extern struct class hpsb_host_class; -extern struct class_simple *hpsb_protocol_class; +extern struct class *hpsb_protocol_class; #endif /* _IEEE1394_CORE_H */ + diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 6a08a89..7419af4 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -2901,7 +2901,7 @@ static int __init init_raw1394(void) hpsb_register_highlevel(&raw1394_highlevel); - if (IS_ERR(class_simple_device_add(hpsb_protocol_class, MKDEV( + if (IS_ERR(class_device_create(hpsb_protocol_class, MKDEV( IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16), NULL, RAW1394_DEVICE_NAME))) { ret = -EFAULT; @@ -2934,8 +2934,8 @@ static int __init init_raw1394(void) out_dev: devfs_remove(RAW1394_DEVICE_NAME); - class_simple_device_remove(MKDEV( - IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16)); + class_device_destroy(hpsb_protocol_class, + MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16)); out_unreg: hpsb_unregister_highlevel(&raw1394_highlevel); out: @@ -2944,8 +2944,8 @@ out: static void __exit cleanup_raw1394(void) { - class_simple_device_remove(MKDEV( - IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16)); + class_device_destroy(hpsb_protocol_class, + MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16)); cdev_del(&raw1394_cdev); devfs_remove(RAW1394_DEVICE_NAME); hpsb_unregister_highlevel(&raw1394_highlevel); diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index d68c465..06759b3 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -1370,7 +1370,7 @@ static void video1394_add_host (struct hpsb_host *host) hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id); minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id; - class_simple_device_add(hpsb_protocol_class, MKDEV( + class_device_create(hpsb_protocol_class, MKDEV( IEEE1394_MAJOR, minor), NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id); devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor), @@ -1384,7 +1384,7 @@ static void video1394_remove_host (struct hpsb_host *host) struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host); if (ohci) { - class_simple_device_remove(MKDEV(IEEE1394_MAJOR, + class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id)); devfs_remove("%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id); } -- cgit v0.10.2 From d253878b3d9ae523c76118f5336a662780ad3757 Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 09:55:22 -0800 Subject: [PATCH] class: convert drivers/scsi/* to use the new class api instead of class_simple Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index c585c7b..89a4a06 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -5608,13 +5608,13 @@ static ssize_t osst_filemark_cnt_show(struct class_device *class_dev, char *buf) CLASS_DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL); -static struct class_simple * osst_sysfs_class; +static struct class *osst_sysfs_class; static int osst_sysfs_valid = 0; static void osst_sysfs_init(void) { - osst_sysfs_class = class_simple_create(THIS_MODULE, "onstream_tape"); + osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape"); if ( IS_ERR(osst_sysfs_class) ) printk(KERN_WARNING "osst :W: Unable to register sysfs class\n"); else @@ -5627,7 +5627,7 @@ static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * if (!osst_sysfs_valid) return; - osst_class_member = class_simple_device_add(osst_sysfs_class, dev, device, "%s", name); + osst_class_member = class_device_create(osst_sysfs_class, dev, device, "%s", name); if (IS_ERR(osst_class_member)) { printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); return; @@ -5645,13 +5645,13 @@ static void osst_sysfs_destroy(dev_t dev) { if (!osst_sysfs_valid) return; - class_simple_device_remove(dev); + class_device_destroy(osst_sysfs_class, dev); } static void osst_sysfs_cleanup(void) { if (osst_sysfs_valid) { - class_simple_destroy(osst_sysfs_class); + class_destroy(osst_sysfs_class); osst_sysfs_valid = 0; } } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 3d1d7bf..51292f2 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1430,7 +1430,7 @@ static struct file_operations sg_fops = { .fasync = sg_fasync, }; -static struct class_simple * sg_sysfs_class; +static struct class *sg_sysfs_class; static int sg_sysfs_valid = 0; @@ -1551,13 +1551,13 @@ sg_add(struct class_device *cl_dev) if (sg_sysfs_valid) { struct class_device * sg_class_member; - sg_class_member = class_simple_device_add(sg_sysfs_class, + sg_class_member = class_device_create(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k), cl_dev->dev, "%s", disk->disk_name); if (IS_ERR(sg_class_member)) printk(KERN_WARNING "sg_add: " - "class_simple_device_add failed\n"); + "class_device_create failed\n"); class_set_devdata(sg_class_member, sdp); error = sysfs_create_link(&scsidp->sdev_gendev.kobj, &sg_class_member->kobj, "generic"); @@ -1636,7 +1636,7 @@ sg_remove(struct class_device *cl_dev) if (sdp) { sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); - class_simple_device_remove(MKDEV(SCSI_GENERIC_MAJOR, k)); + class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k)); cdev_del(sdp->cdev); sdp->cdev = NULL; devfs_remove("%s/generic", scsidp->devfs_name); @@ -1677,7 +1677,7 @@ init_sg(void) SG_MAX_DEVS, "sg"); if (rc) return rc; - sg_sysfs_class = class_simple_create(THIS_MODULE, "scsi_generic"); + sg_sysfs_class = class_create(THIS_MODULE, "scsi_generic"); if ( IS_ERR(sg_sysfs_class) ) { rc = PTR_ERR(sg_sysfs_class); goto err_out; @@ -1690,7 +1690,7 @@ init_sg(void) #endif /* CONFIG_SCSI_PROC_FS */ return 0; } - class_simple_destroy(sg_sysfs_class); + class_destroy(sg_sysfs_class); err_out: unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); return rc; @@ -1703,7 +1703,7 @@ exit_sg(void) sg_proc_cleanup(); #endif /* CONFIG_SCSI_PROC_FS */ scsi_unregister_interface(&sg_interface); - class_simple_destroy(sg_sysfs_class); + class_destroy(sg_sysfs_class); sg_sysfs_valid = 0; unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 03b902c..0291a8f 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -84,7 +84,7 @@ static int try_wdio = 1; static int st_dev_max; static int st_nr_dev; -static struct class_simple *st_sysfs_class; +static struct class *st_sysfs_class; MODULE_AUTHOR("Kai Makisara"); MODULE_DESCRIPTION("SCSI Tape Driver"); @@ -4024,8 +4024,9 @@ out_free_tape: if (STm->cdevs[j]) { if (cdev == STm->cdevs[j]) cdev = NULL; - class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR, - TAPE_MINOR(i, mode, j))); + class_device_destroy(st_sysfs_class, + MKDEV(SCSI_TAPE_MAJOR, + TAPE_MINOR(i, mode, j))); cdev_del(STm->cdevs[j]); } } @@ -4068,8 +4069,9 @@ static int st_remove(struct device *dev) devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[j]); devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[j]); for (j=0; j < 2; j++) { - class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR, - TAPE_MINOR(i, mode, j))); + class_device_destroy(st_sysfs_class, + MKDEV(SCSI_TAPE_MAJOR, + TAPE_MINOR(i, mode, j))); cdev_del(tpnt->modes[mode].cdevs[j]); tpnt->modes[mode].cdevs[j] = NULL; } @@ -4134,7 +4136,7 @@ static int __init init_st(void) "st: Version %s, fixed bufsize %d, s/g segs %d\n", verstr, st_fixed_buffer_size, st_max_sg_segs); - st_sysfs_class = class_simple_create(THIS_MODULE, "scsi_tape"); + st_sysfs_class = class_create(THIS_MODULE, "scsi_tape"); if (IS_ERR(st_sysfs_class)) { st_sysfs_class = NULL; printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n"); @@ -4148,7 +4150,7 @@ static int __init init_st(void) return 0; } if (st_sysfs_class) - class_simple_destroy(st_sysfs_class); + class_destroy(st_sysfs_class); unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), ST_MAX_TAPE_ENTRIES); @@ -4161,7 +4163,7 @@ static int __init init_st(void) static void __exit exit_st(void) { if (st_sysfs_class) - class_simple_destroy(st_sysfs_class); + class_destroy(st_sysfs_class); st_sysfs_class = NULL; do_remove_driverfs_files(); scsi_unregister_driver(&st_template.gendrv); @@ -4284,12 +4286,12 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) snprintf(name, 10, "%s%s%s", rew ? "n" : "", STp->disk->disk_name, st_formats[i]); st_class_member = - class_simple_device_add(st_sysfs_class, - MKDEV(SCSI_TAPE_MAJOR, - TAPE_MINOR(dev_num, mode, rew)), - &STp->device->sdev_gendev, "%s", name); + class_device_create(st_sysfs_class, + MKDEV(SCSI_TAPE_MAJOR, + TAPE_MINOR(dev_num, mode, rew)), + &STp->device->sdev_gendev, "%s", name); if (IS_ERR(st_class_member)) { - printk(KERN_WARNING "st%d: class_simple_device_add failed\n", + printk(KERN_WARNING "st%d: class_device_create failed\n", dev_num); goto out; } -- cgit v0.10.2 From 8874b414ffe037c39e73bb262ddf69653a13c0a4 Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 09:56:34 -0800 Subject: [PATCH] class: convert arch/* to use the new class api instead of class_simple Signed-off-by: Greg Kroah-Hartman diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c index 2e27563..4647db4 100644 --- a/arch/i386/kernel/cpuid.c +++ b/arch/i386/kernel/cpuid.c @@ -45,7 +45,7 @@ #include #include -static struct class_simple *cpuid_class; +static struct class *cpuid_class; #ifdef CONFIG_SMP @@ -158,12 +158,12 @@ static struct file_operations cpuid_fops = { .open = cpuid_open, }; -static int cpuid_class_simple_device_add(int i) +static int cpuid_class_device_create(int i) { int err = 0; struct class_device *class_err; - class_err = class_simple_device_add(cpuid_class, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i); + class_err = class_device_create(cpuid_class, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i); if (IS_ERR(class_err)) err = PTR_ERR(class_err); return err; @@ -175,10 +175,10 @@ static int __devinit cpuid_class_cpu_callback(struct notifier_block *nfb, unsign switch (action) { case CPU_ONLINE: - cpuid_class_simple_device_add(cpu); + cpuid_class_device_create(cpu); break; case CPU_DEAD: - class_simple_device_remove(MKDEV(CPUID_MAJOR, cpu)); + class_device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu)); break; } return NOTIFY_OK; @@ -200,13 +200,13 @@ static int __init cpuid_init(void) err = -EBUSY; goto out; } - cpuid_class = class_simple_create(THIS_MODULE, "cpuid"); + cpuid_class = class_create(THIS_MODULE, "cpuid"); if (IS_ERR(cpuid_class)) { err = PTR_ERR(cpuid_class); goto out_chrdev; } for_each_online_cpu(i) { - err = cpuid_class_simple_device_add(i); + err = cpuid_class_device_create(i); if (err != 0) goto out_class; } @@ -218,9 +218,9 @@ static int __init cpuid_init(void) out_class: i = 0; for_each_online_cpu(i) { - class_simple_device_remove(MKDEV(CPUID_MAJOR, i)); + class_device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, i)); } - class_simple_destroy(cpuid_class); + class_destroy(cpuid_class); out_chrdev: unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); out: @@ -232,8 +232,8 @@ static void __exit cpuid_exit(void) int cpu = 0; for_each_online_cpu(cpu) - class_simple_device_remove(MKDEV(CPUID_MAJOR, cpu)); - class_simple_destroy(cpuid_class); + class_device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu)); + class_destroy(cpuid_class); unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); unregister_cpu_notifier(&cpuid_class_cpu_notifier); } diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c index 05d9f8f..b2f03c3 100644 --- a/arch/i386/kernel/msr.c +++ b/arch/i386/kernel/msr.c @@ -44,7 +44,7 @@ #include #include -static struct class_simple *msr_class; +static struct class *msr_class; /* Note: "err" is handled in a funny way below. Otherwise one version of gcc or another breaks. */ @@ -260,12 +260,12 @@ static struct file_operations msr_fops = { .open = msr_open, }; -static int msr_class_simple_device_add(int i) +static int msr_class_device_create(int i) { int err = 0; struct class_device *class_err; - class_err = class_simple_device_add(msr_class, MKDEV(MSR_MAJOR, i), NULL, "msr%d",i); + class_err = class_device_create(msr_class, MKDEV(MSR_MAJOR, i), NULL, "msr%d",i); if (IS_ERR(class_err)) err = PTR_ERR(class_err); return err; @@ -277,10 +277,10 @@ static int __devinit msr_class_cpu_callback(struct notifier_block *nfb, unsigned switch (action) { case CPU_ONLINE: - msr_class_simple_device_add(cpu); + msr_class_device_create(cpu); break; case CPU_DEAD: - class_simple_device_remove(MKDEV(MSR_MAJOR, cpu)); + class_device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu)); break; } return NOTIFY_OK; @@ -302,13 +302,13 @@ static int __init msr_init(void) err = -EBUSY; goto out; } - msr_class = class_simple_create(THIS_MODULE, "msr"); + msr_class = class_create(THIS_MODULE, "msr"); if (IS_ERR(msr_class)) { err = PTR_ERR(msr_class); goto out_chrdev; } for_each_online_cpu(i) { - err = msr_class_simple_device_add(i); + err = msr_class_device_create(i); if (err != 0) goto out_class; } @@ -320,8 +320,8 @@ static int __init msr_init(void) out_class: i = 0; for_each_online_cpu(i) - class_simple_device_remove(MKDEV(MSR_MAJOR, i)); - class_simple_destroy(msr_class); + class_device_destroy(msr_class, MKDEV(MSR_MAJOR, i)); + class_destroy(msr_class); out_chrdev: unregister_chrdev(MSR_MAJOR, "cpu/msr"); out: @@ -332,8 +332,8 @@ static void __exit msr_exit(void) { int cpu = 0; for_each_online_cpu(cpu) - class_simple_device_remove(MKDEV(MSR_MAJOR, cpu)); - class_simple_destroy(msr_class); + class_device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu)); + class_destroy(msr_class); unregister_chrdev(MSR_MAJOR, "cpu/msr"); unregister_cpu_notifier(&msr_class_cpu_notifier); } -- cgit v0.10.2 From 56b2293595b2eb52cc2aa2baf92c6cfa8265f9d5 Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 10:01:41 -0800 Subject: [PATCH] class: convert drivers/* to use the new class api instead of class_simple Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 12dee8e..04fb606 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -58,7 +58,7 @@ MODULE_LICENSE("GPL"); /* -------- driver information -------------------------------------- */ -static struct class_simple *capi_class; +static struct class *capi_class; static int capi_major = 68; /* allocated */ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -1499,20 +1499,20 @@ static int __init capi_init(void) return -EIO; } - capi_class = class_simple_create(THIS_MODULE, "capi"); + capi_class = class_create(THIS_MODULE, "capi"); if (IS_ERR(capi_class)) { unregister_chrdev(capi_major, "capi20"); return PTR_ERR(capi_class); } - class_simple_device_add(capi_class, MKDEV(capi_major, 0), NULL, "capi"); + class_device_create(capi_class, MKDEV(capi_major, 0), NULL, "capi"); devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR, "isdn/capi20"); #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if (capinc_tty_init() < 0) { - class_simple_device_remove(MKDEV(capi_major, 0)); - class_simple_destroy(capi_class); + class_device_destroy(capi_class, MKDEV(capi_major, 0)); + class_destroy(capi_class); unregister_chrdev(capi_major, "capi20"); return -ENOMEM; } @@ -1539,8 +1539,8 @@ static void __exit capi_exit(void) { proc_exit(); - class_simple_device_remove(MKDEV(capi_major, 0)); - class_simple_destroy(capi_class); + class_device_destroy(capi_class, MKDEV(capi_major, 0)); + class_destroy(capi_class); unregister_chrdev(capi_major, "capi20"); devfs_remove("isdn/capi20"); diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 7297c77..493e2af 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -77,7 +77,7 @@ static struct adb_driver *adb_driver_list[] = { NULL }; -static struct class_simple *adb_dev_class; +static struct class *adb_dev_class; struct adb_driver *adb_controller; struct notifier_block *adb_client_list = NULL; @@ -902,9 +902,8 @@ adbdev_init(void) devfs_mk_cdev(MKDEV(ADB_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "adb"); - adb_dev_class = class_simple_create(THIS_MODULE, "adb"); - if (IS_ERR(adb_dev_class)) { + adb_dev_class = class_create(THIS_MODULE, "adb"); + if (IS_ERR(adb_dev_class)) return; - } - class_simple_device_add(adb_dev_class, MKDEV(ADB_MAJOR, 0), NULL, "adb"); + class_device_create(adb_dev_class, MKDEV(ADB_MAJOR, 0), NULL, "adb"); } diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 9d9662f4..4b7adca 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -56,8 +56,7 @@ static const char * const dnames[] = { #define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) -struct class_simple *dvb_class; -EXPORT_SYMBOL(dvb_class); +static struct class *dvb_class; static struct dvb_device* dvbdev_find_device (int minor) { @@ -236,8 +235,8 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, S_IFCHR | S_IRUSR | S_IWUSR, "dvb/adapter%d/%s%d", adap->num, dnames[type], id); - class_simple_device_add(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - NULL, "dvb%d.%s%d", adap->num, dnames[type], id); + class_device_create(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + NULL, "dvb%d.%s%d", adap->num, dnames[type], id); dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, nums2minor(adap->num, type, id), @@ -256,7 +255,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev) devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id); - class_simple_device_remove(MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, + class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, dvbdev->type, dvbdev->id))); list_del (&dvbdev->list_head); @@ -412,7 +411,7 @@ static int __init init_dvbdev(void) devfs_mk_dir("dvb"); - dvb_class = class_simple_create(THIS_MODULE, "dvb"); + dvb_class = class_create(THIS_MODULE, "dvb"); if (IS_ERR(dvb_class)) { retval = PTR_ERR(dvb_class); goto error; @@ -429,7 +428,7 @@ error: static void __exit exit_dvbdev(void) { devfs_remove("dvb"); - class_simple_destroy(dvb_class); + class_destroy(dvb_class); cdev_del(&dvb_device_cdev); unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); } diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index ad4b58a..ab726ab 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -273,7 +273,7 @@ static int ppp_connect_channel(struct channel *pch, int unit); static int ppp_disconnect_channel(struct channel *pch); static void ppp_destroy_channel(struct channel *pch); -static struct class_simple *ppp_class; +static struct class *ppp_class; /* Translates a PPP protocol number to a NP index (NP == network protocol) */ static inline int proto_to_npindex(int proto) @@ -858,12 +858,12 @@ static int __init ppp_init(void) printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n"); err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); if (!err) { - ppp_class = class_simple_create(THIS_MODULE, "ppp"); + ppp_class = class_create(THIS_MODULE, "ppp"); if (IS_ERR(ppp_class)) { err = PTR_ERR(ppp_class); goto out_chrdev; } - class_simple_device_add(ppp_class, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); + class_device_create(ppp_class, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "ppp"); if (err) @@ -876,8 +876,8 @@ out: return err; out_class: - class_simple_device_remove(MKDEV(PPP_MAJOR,0)); - class_simple_destroy(ppp_class); + class_device_destroy(ppp_class, MKDEV(PPP_MAJOR,0)); + class_destroy(ppp_class); out_chrdev: unregister_chrdev(PPP_MAJOR, "ppp"); goto out; @@ -2654,8 +2654,8 @@ static void __exit ppp_cleanup(void) if (unregister_chrdev(PPP_MAJOR, "ppp") != 0) printk(KERN_ERR "PPP: failed to unregister PPP device\n"); devfs_remove("ppp"); - class_simple_device_remove(MKDEV(PPP_MAJOR, 0)); - class_simple_destroy(ppp_class); + class_device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); + class_destroy(ppp_class); } /* diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 921a573..7ff814f 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -235,7 +235,7 @@ static int dma[MAX_CARDS+1]; static int irq[MAX_CARDS+1] = { -1, -1, -1, -1, -1, -1, 0, }; /* for class stuff*/ -static struct class_simple *cosa_class; +static struct class *cosa_class; #ifdef MODULE module_param_array(io, int, NULL, 0); @@ -394,19 +394,19 @@ static int __init cosa_init(void) goto out; } devfs_mk_dir("cosa"); - cosa_class = class_simple_create(THIS_MODULE, "cosa"); + cosa_class = class_create(THIS_MODULE, "cosa"); if (IS_ERR(cosa_class)) { err = PTR_ERR(cosa_class); goto out_chrdev; } for (i=0; iclass_device = class_simple_device_add( + tcd->class_device = class_device_create( tape_class, tcd->char_device->dev, device, @@ -101,7 +101,7 @@ void unregister_tape_dev(struct tape_class_device *tcd) &tcd->class_device->dev->kobj, tcd->mode_name ); - class_simple_device_remove(tcd->char_device->dev); + class_device_destroy(tape_class, tcd->char_device->dev); cdev_del(tcd->char_device); kfree(tcd); } @@ -111,14 +111,14 @@ EXPORT_SYMBOL(unregister_tape_dev); static int __init tape_init(void) { - tape_class = class_simple_create(THIS_MODULE, "tape390"); + tape_class = class_create(THIS_MODULE, "tape390"); return 0; } static void __exit tape_exit(void) { - class_simple_destroy(tape_class); + class_destroy(tape_class); tape_class = NULL; } diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index edf50d2..724ad87 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -703,7 +703,7 @@ static struct attribute_group vmlogrdr_attr_group = { .attrs = vmlogrdr_attrs, }; -static struct class_simple *vmlogrdr_class; +static struct class *vmlogrdr_class; static struct device_driver vmlogrdr_driver = { .name = "vmlogrdr", .bus = &iucv_bus, @@ -727,7 +727,7 @@ vmlogrdr_register_driver(void) { goto unregdriver; } - vmlogrdr_class = class_simple_create(THIS_MODULE, "vmlogrdr"); + vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); if (IS_ERR(vmlogrdr_class)) { printk(KERN_ERR "vmlogrdr: failed to create class.\n"); ret=PTR_ERR(vmlogrdr_class); @@ -746,7 +746,7 @@ unregdriver: static void vmlogrdr_unregister_driver(void) { - class_simple_destroy(vmlogrdr_class); + class_destroy(vmlogrdr_class); vmlogrdr_class = NULL; driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); driver_unregister(&vmlogrdr_driver); @@ -786,7 +786,7 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { device_unregister(dev); return ret; } - priv->class_device = class_simple_device_add( + priv->class_device = class_device_create( vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num), dev, @@ -806,7 +806,7 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { - class_simple_device_remove(MKDEV(vmlogrdr_major, priv->minor_num)); + class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num)); if (priv->device != NULL) { sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); device_unregister(priv->device); diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 38ed222..dfcbd05 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -68,7 +68,7 @@ static struct file_operations usb_fops = { .open = usb_open, }; -static struct class_simple *usb_class; +static struct class *usb_class; int usb_major_init(void) { @@ -80,9 +80,9 @@ int usb_major_init(void) goto out; } - usb_class = class_simple_create(THIS_MODULE, "usb"); + usb_class = class_create(THIS_MODULE, "usb"); if (IS_ERR(usb_class)) { - err("class_simple_create failed for usb devices"); + err("class_create failed for usb devices"); unregister_chrdev(USB_MAJOR, "usb"); goto out; } @@ -95,7 +95,7 @@ out: void usb_major_cleanup(void) { - class_simple_destroy(usb_class); + class_destroy(usb_class); devfs_remove("usb"); unregister_chrdev(USB_MAJOR, "usb"); } @@ -171,7 +171,7 @@ int usb_register_dev(struct usb_interface *intf, ++temp; else temp = name; - intf->class_dev = class_simple_device_add(usb_class, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp); + intf->class_dev = class_device_create(usb_class, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp); if (IS_ERR(intf->class_dev)) { spin_lock (&minor_lock); usb_minors[intf->minor] = NULL; @@ -220,7 +220,7 @@ void usb_deregister_dev(struct usb_interface *intf, snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); devfs_remove (name); - class_simple_device_remove(MKDEV(USB_MAJOR, intf->minor)); + class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor)); intf->class_dev = NULL; intf->minor = -1; } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 7705070..8cef020 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1040,7 +1040,7 @@ static struct file_operations fb_fops = { #endif }; -static struct class_simple *fb_class; +static struct class *fb_class; /** * register_framebuffer - registers a frame buffer device @@ -1066,7 +1066,7 @@ register_framebuffer(struct fb_info *fb_info) break; fb_info->node = i; - fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i), + fb_info->class_device = class_device_create(fb_class, MKDEV(FB_MAJOR, i), fb_info->device, "fb%d", i); if (IS_ERR(fb_info->class_device)) { /* Not fatal */ @@ -1134,7 +1134,7 @@ unregister_framebuffer(struct fb_info *fb_info) registered_fb[i]=NULL; num_registered_fb--; fb_cleanup_class_device(fb_info); - class_simple_device_remove(MKDEV(FB_MAJOR, i)); + class_device_destroy(fb_class, MKDEV(FB_MAJOR, i)); return 0; } @@ -1197,7 +1197,7 @@ fbmem_init(void) if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) printk("unable to get major %d for fb devs\n", FB_MAJOR); - fb_class = class_simple_create(THIS_MODULE, "graphics"); + fb_class = class_create(THIS_MODULE, "graphics"); if (IS_ERR(fb_class)) { printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class)); fb_class = NULL; @@ -1210,7 +1210,7 @@ module_init(fbmem_init); static void __exit fbmem_exit(void) { - class_simple_destroy(fb_class); + class_destroy(fb_class); } module_exit(fbmem_exit); -- cgit v0.10.2 From 5cebfb759cc75208c04590ad7f4485cdd822cf46 Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Mon, 2 May 2005 23:35:45 -0400 Subject: [PATCH] USB: trivial error path fix Trivial fix to USB class-creation error path; please apply. Signed-off-by: Mark M. Hoffman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index dfcbd05..65ca131 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -82,6 +82,7 @@ int usb_major_init(void) usb_class = class_create(THIS_MODULE, "usb"); if (IS_ERR(usb_class)) { + error = PTR_ERR(usb_class); err("class_create failed for usb devices"); unregister_chrdev(USB_MAJOR, "usb"); goto out; -- cgit v0.10.2 From 1db560afe629b682c45a7f4ba7edf98b4ee28518 Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 10:02:26 -0800 Subject: [PATCH] class: convert the remaining class_simple users in the kernel to usee the new class api Signed-off-by: Greg Kroah-Hartman diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index ef001a9..3d1cce3 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -61,7 +61,7 @@ unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */ struct venus_comm coda_comms[MAX_CODADEVS]; -static struct class_simple *coda_psdev_class; +static struct class *coda_psdev_class; /* * Device operations @@ -363,14 +363,14 @@ static int init_coda_psdev(void) CODA_PSDEV_MAJOR); return -EIO; } - coda_psdev_class = class_simple_create(THIS_MODULE, "coda"); + coda_psdev_class = class_create(THIS_MODULE, "coda"); if (IS_ERR(coda_psdev_class)) { err = PTR_ERR(coda_psdev_class); goto out_chrdev; } devfs_mk_dir ("coda"); for (i = 0; i < MAX_CODADEVS; i++) { - class_simple_device_add(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR,i), + class_device_create(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR,i), NULL, "cfs%d", i); err = devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i), S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i); @@ -382,8 +382,8 @@ static int init_coda_psdev(void) out_class: for (i = 0; i < MAX_CODADEVS; i++) - class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i)); - class_simple_destroy(coda_psdev_class); + class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); + class_destroy(coda_psdev_class); out_chrdev: unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); out: @@ -425,10 +425,10 @@ static int __init init_coda(void) return 0; out: for (i = 0; i < MAX_CODADEVS; i++) { - class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i)); + class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); devfs_remove("coda/%d", i); } - class_simple_destroy(coda_psdev_class); + class_destroy(coda_psdev_class); devfs_remove("coda"); unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); coda_sysctl_clean(); @@ -447,10 +447,10 @@ static void __exit exit_coda(void) printk("coda: failed to unregister filesystem\n"); } for (i = 0; i < MAX_CODADEVS; i++) { - class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i)); + class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); devfs_remove("coda/%d", i); } - class_simple_destroy(coda_psdev_class); + class_destroy(coda_psdev_class); devfs_remove("coda"); unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); coda_sysctl_clean(); -- cgit v0.10.2 From 2fc68447df5c76cf254037047b4b02551bd5d760 Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 10:02:56 -0800 Subject: [PATCH] class: add kerneldoc for the new class functions. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/class.c b/drivers/base/class.c index a3b006b..479c125 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -173,6 +173,17 @@ static void class_device_create_release(struct class_device *class_dev) kfree(class_dev); } +/** + * class_create - create a struct class structure + * @owner: pointer to the module that is to "own" this struct class + * @name: pointer to a string for the name of this class. + * + * This is used to create a struct class pointer that can then be used + * in calls to class_device_create(). + * + * Note, the pointer created here is to be destroyed when finished by + * making a call to class_destroy(). + */ struct class *class_create(struct module *owner, char *name) { struct class *cls; @@ -201,6 +212,13 @@ error: return ERR_PTR(retval); } +/** + * class_destroy - destroys a struct class structure + * @cs: pointer to the struct class that is to be destroyed + * + * Note, the pointer to be destroyed must have been created with a call + * to class_create(). + */ void class_destroy(struct class *cls) { if ((cls == NULL) || (IS_ERR(cls))) @@ -505,6 +523,23 @@ int class_device_register(struct class_device *class_dev) return class_device_add(class_dev); } +/** + * class_device_create - creates a class device and registers it with sysfs + * @cs: pointer to the struct class that this device should be registered to. + * @dev: the dev_t for the char device to be added. + * @device: a pointer to a struct device that is assiociated with this class device. + * @fmt: string for the class device's name + * + * This function can be used by char device classes. A struct + * class_device will be created in sysfs, registered to the specified + * class. A "dev" file will be created, showing the dev_t for the + * device. The pointer to the struct class_device will be returned from + * the call. Any further sysfs files that might be required can be + * created using this pointer. + * + * Note: the struct class passed to this function must have previously + * been created with a call to class_create(). + */ struct class_device *class_device_create(struct class *cls, dev_t devt, struct device *device, char *fmt, ...) { @@ -578,6 +613,14 @@ void class_device_unregister(struct class_device *class_dev) class_device_put(class_dev); } +/** + * class_device_destroy - removes a class device that was created with class_device_create() + * @cls: the pointer to the struct class that this device was registered * with. + * @dev: the dev_t of the device that was previously registered. + * + * This call unregisters and cleans up a class device that was created with a + * call to class_device_create() + */ void class_device_destroy(struct class *cls, dev_t devt) { struct class_device *class_dev = NULL; -- cgit v0.10.2 From cd987d38cc59053e0bab8150ffaca33b109067f3 Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 11:12:38 -0800 Subject: [PATCH] class: remove class_simple code, as no one in the tree is using it anymore. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/Makefile b/drivers/base/Makefile index a47928a2..771f6c8 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -1,7 +1,7 @@ # Makefile for the Linux device tree obj-y := core.o sys.o bus.o \ - driver.o class.o class_simple.o platform.o \ + driver.o class.o platform.o \ cpu.o firmware.o init.o map.o dmapool.o \ attribute_container.o transport_class.o obj-y += power/ diff --git a/drivers/base/class_simple.c b/drivers/base/class_simple.c deleted file mode 100644 index 27699eb..0000000 --- a/drivers/base/class_simple.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * class_simple.c - a "simple" interface for classes for simple char devices. - * - * Copyright (c) 2003-2004 Greg Kroah-Hartman - * Copyright (c) 2003-2004 IBM Corp. - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include - -struct class_simple { - struct class class; -}; -#define to_class_simple(d) container_of(d, struct class_simple, class) - -struct simple_dev { - struct list_head node; - struct class_device class_dev; -}; -#define to_simple_dev(d) container_of(d, struct simple_dev, class_dev) - -static LIST_HEAD(simple_dev_list); -static DEFINE_SPINLOCK(simple_dev_list_lock); - -static void release_simple_dev(struct class_device *class_dev) -{ - struct simple_dev *s_dev = to_simple_dev(class_dev); - kfree(s_dev); -} - -static void class_simple_release(struct class *class) -{ - struct class_simple *cs = to_class_simple(class); - kfree(cs); -} - -/** - * class_simple_create - create a struct class_simple structure - * @owner: pointer to the module that is to "own" this struct class_simple - * @name: pointer to a string for the name of this class. - * - * This is used to create a struct class_simple pointer that can then be used - * in calls to class_simple_device_add(). This is used when you do not wish to - * create a full blown class support for a type of char devices. - * - * Note, the pointer created here is to be destroyed when finished by making a - * call to class_simple_destroy(). - */ -struct class_simple *class_simple_create(struct module *owner, char *name) -{ - struct class_simple *cs; - int retval; - - cs = kmalloc(sizeof(*cs), GFP_KERNEL); - if (!cs) { - retval = -ENOMEM; - goto error; - } - memset(cs, 0x00, sizeof(*cs)); - - cs->class.name = name; - cs->class.class_release = class_simple_release; - cs->class.release = release_simple_dev; - - retval = class_register(&cs->class); - if (retval) - goto error; - - return cs; - -error: - kfree(cs); - return ERR_PTR(retval); -} -EXPORT_SYMBOL(class_simple_create); - -/** - * class_simple_destroy - destroys a struct class_simple structure - * @cs: pointer to the struct class_simple that is to be destroyed - * - * Note, the pointer to be destroyed must have been created with a call to - * class_simple_create(). - */ -void class_simple_destroy(struct class_simple *cs) -{ - if ((cs == NULL) || (IS_ERR(cs))) - return; - - class_unregister(&cs->class); -} -EXPORT_SYMBOL(class_simple_destroy); - -/** - * class_simple_device_add - adds a class device to sysfs for a character driver - * @cs: pointer to the struct class_simple that this device should be registered to. - * @dev: the dev_t for the device to be added. - * @device: a pointer to a struct device that is assiociated with this class device. - * @fmt: string for the class device's name - * - * This function can be used by simple char device classes that do not - * implement their own class device registration. A struct class_device will - * be created in sysfs, registered to the specified class. A "dev" file will - * be created, showing the dev_t for the device. The pointer to the struct - * class_device will be returned from the call. Any further sysfs files that - * might be required can be created using this pointer. - * Note: the struct class_simple passed to this function must have previously been - * created with a call to class_simple_create(). - */ -struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev, struct device *device, const char *fmt, ...) -{ - va_list args; - struct simple_dev *s_dev = NULL; - int retval; - - if ((cs == NULL) || (IS_ERR(cs))) { - retval = -ENODEV; - goto error; - } - - s_dev = kmalloc(sizeof(*s_dev), GFP_KERNEL); - if (!s_dev) { - retval = -ENOMEM; - goto error; - } - memset(s_dev, 0x00, sizeof(*s_dev)); - - s_dev->class_dev.devt = dev; - s_dev->class_dev.dev = device; - s_dev->class_dev.class = &cs->class; - - va_start(args, fmt); - vsnprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, fmt, args); - va_end(args); - retval = class_device_register(&s_dev->class_dev); - if (retval) - goto error; - - spin_lock(&simple_dev_list_lock); - list_add(&s_dev->node, &simple_dev_list); - spin_unlock(&simple_dev_list_lock); - - return &s_dev->class_dev; - -error: - kfree(s_dev); - return ERR_PTR(retval); -} -EXPORT_SYMBOL(class_simple_device_add); - -/** - * class_simple_set_hotplug - set the hotplug callback in the embedded struct class - * @cs: pointer to the struct class_simple to hold the pointer - * @hotplug: function pointer to the hotplug function - * - * Implement and set a hotplug function to add environment variables specific to this - * class on the hotplug event. - */ -int class_simple_set_hotplug(struct class_simple *cs, - int (*hotplug)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size)) -{ - if ((cs == NULL) || (IS_ERR(cs))) - return -ENODEV; - cs->class.hotplug = hotplug; - return 0; -} -EXPORT_SYMBOL(class_simple_set_hotplug); - -/** - * class_simple_device_remove - removes a class device that was created with class_simple_device_add() - * @dev: the dev_t of the device that was previously registered. - * - * This call unregisters and cleans up a class device that was created with a - * call to class_device_simple_add() - */ -void class_simple_device_remove(dev_t dev) -{ - struct simple_dev *s_dev = NULL; - int found = 0; - - spin_lock(&simple_dev_list_lock); - list_for_each_entry(s_dev, &simple_dev_list, node) { - if (s_dev->class_dev.devt == dev) { - found = 1; - break; - } - } - if (found) { - list_del(&s_dev->node); - spin_unlock(&simple_dev_list_lock); - class_device_unregister(&s_dev->class_dev); - } else { - spin_unlock(&simple_dev_list_lock); - } -} -EXPORT_SYMBOL(class_simple_device_remove); diff --git a/include/linux/device.h b/include/linux/device.h index 73250d0..68a9535 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -44,7 +44,6 @@ struct device; struct device_driver; struct class; struct class_device; -struct class_simple; struct bus_type { const char * name; @@ -254,15 +253,6 @@ extern struct class_device *class_device_create(struct class *cls, dev_t devt, __attribute__((format(printf,4,5))); extern void class_device_destroy(struct class *cls, dev_t devt); -/* interface for class simple stuff */ -extern struct class_simple *class_simple_create(struct module *owner, char *name); -extern void class_simple_destroy(struct class_simple *cs); -extern struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev, struct device *device, const char *fmt, ...) - __attribute__((format(printf,4,5))); -extern int class_simple_set_hotplug(struct class_simple *, - int (*hotplug)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size)); -extern void class_simple_device_remove(dev_t dev); - struct device { struct list_head node; /* node in sibling list */ -- cgit v0.10.2 From 733a366c34aea88def75dee478f92233410ab3c4 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 5 May 2005 15:06:38 -0700 Subject: [PATCH] fix "make mandocs" after class_simple.c removal Due to the removal of class_simple.c, "make mandocs" no longer works. This patch fixes this issue. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 757cef8..bb6a010 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -338,7 +338,6 @@ X!Earch/i386/kernel/mca.c X!Iinclude/linux/device.h --> !Edrivers/base/driver.c -!Edrivers/base/class_simple.c !Edrivers/base/core.c !Edrivers/base/firmware_class.c !Edrivers/base/transport_class.c -- cgit v0.10.2 From eb51b65005737b777e0709683b061d5f82aefd97 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 5 May 2005 15:06:38 -0700 Subject: [PATCH] fix up ipmi code after class_simple.c removal Cc: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 6dc765d..88d1ad6 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -520,7 +520,7 @@ MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device. By" " interface. Other values will set the major device number" " to that value."); -static struct class_simple *ipmi_class; +static struct class *ipmi_class; static void ipmi_new_smi(int if_num) { @@ -529,12 +529,12 @@ static void ipmi_new_smi(int if_num) devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, "ipmidev/%d", if_num); - class_simple_device_add(ipmi_class, dev, NULL, "ipmi%d", if_num); + class_device_create(ipmi_class, dev, NULL, "ipmi%d", if_num); } static void ipmi_smi_gone(int if_num) { - class_simple_device_remove(MKDEV(ipmi_major, if_num)); + class_device_destroy(ipmi_class, MKDEV(ipmi_major, if_num)); devfs_remove("ipmidev/%d", if_num); } @@ -555,7 +555,7 @@ static __init int init_ipmi_devintf(void) printk(KERN_INFO "ipmi device interface version " IPMI_DEVINTF_VERSION "\n"); - ipmi_class = class_simple_create(THIS_MODULE, "ipmi"); + ipmi_class = class_create(THIS_MODULE, "ipmi"); if (IS_ERR(ipmi_class)) { printk(KERN_ERR "ipmi: can't register device class\n"); return PTR_ERR(ipmi_class); @@ -563,7 +563,7 @@ static __init int init_ipmi_devintf(void) rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops); if (rv < 0) { - class_simple_destroy(ipmi_class); + class_destroy(ipmi_class); printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major); return rv; } @@ -577,7 +577,7 @@ static __init int init_ipmi_devintf(void) rv = ipmi_smi_watcher_register(&smi_watcher); if (rv) { unregister_chrdev(ipmi_major, DEVICE_NAME); - class_simple_destroy(ipmi_class); + class_destroy(ipmi_class); printk(KERN_WARNING "ipmi: can't register smi watcher\n"); return rv; } @@ -588,7 +588,7 @@ module_init(init_ipmi_devintf); static __exit void cleanup_ipmi(void) { - class_simple_destroy(ipmi_class); + class_destroy(ipmi_class); ipmi_smi_watcher_unregister(&smi_watcher); devfs_remove(DEVICE_NAME); unregister_chrdev(ipmi_major, DEVICE_NAME); -- cgit v0.10.2 From af70316af182f4716cc5eec7e0d27fc731d164bd Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Mon, 21 Mar 2005 10:41:04 -0800 Subject: [PATCH] Add a semaphore to struct device to synchronize calls to its driver. This adds a per-device semaphore that is taken before every call from the core to a driver method. This prevents e.g. simultaneous calls to the ->suspend() or ->resume() and ->probe() or ->release(), potentially saving a whole lot of headaches. It also moves us a step closer to removing the bus rwsem, since it protects the fields in struct device that are modified by the core. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 80ce88d..aa27f76 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -283,18 +283,22 @@ void device_bind_driver(struct device * dev) */ int driver_probe_device(struct device_driver * drv, struct device * dev) { + int error = 0; + if (drv->bus->match && !drv->bus->match(dev, drv)) return -ENODEV; + down(&dev->sem); dev->driver = drv; if (drv->probe) { - int error = drv->probe(dev); + error = drv->probe(dev); if (error) { dev->driver = NULL; + up(&dev->sem); return error; } } - + up(&dev->sem); device_bind_driver(dev); return 0; } @@ -385,7 +389,10 @@ void driver_attach(struct device_driver * drv) void device_release_driver(struct device * dev) { - struct device_driver * drv = dev->driver; + struct device_driver * drv; + + down(&dev->sem); + drv = dev->driver; if (drv) { sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&dev->kobj, "driver"); @@ -394,6 +401,7 @@ void device_release_driver(struct device * dev) drv->remove(dev); dev->driver = NULL; } + up(&dev->sem); } diff --git a/drivers/base/core.c b/drivers/base/core.c index a293a78..9344082 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -212,6 +212,7 @@ void device_initialize(struct device *dev) INIT_LIST_HEAD(&dev->driver_list); INIT_LIST_HEAD(&dev->bus_list); INIT_LIST_HEAD(&dev->dma_pools); + init_MUTEX(&dev->sem); } /** diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 2646897..bdd96b0 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -22,6 +22,9 @@ extern int sysdev_resume(void); int resume_device(struct device * dev) { + int error = 0; + + down(&dev->sem); if (dev->power.pm_parent && dev->power.pm_parent->power.power_state) { dev_err(dev, "PM: resume from %d, parent %s still %d\n", @@ -31,9 +34,10 @@ int resume_device(struct device * dev) } if (dev->bus && dev->bus->resume) { dev_dbg(dev,"resuming\n"); - return dev->bus->resume(dev); + error = dev->bus->resume(dev); } - return 0; + up(&dev->sem); + return error; } diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 0ec44ef..807e13f 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -39,6 +39,7 @@ int suspend_device(struct device * dev, pm_message_t state) { int error = 0; + down(&dev->sem); if (dev->power.power_state) { dev_dbg(dev, "PM: suspend %d-->%d\n", dev->power.power_state, state); @@ -58,7 +59,7 @@ int suspend_device(struct device * dev, pm_message_t state) dev_dbg(dev, "suspending\n"); error = dev->bus->suspend(dev, state); } - + up(&dev->sem); return error; } diff --git a/include/linux/device.h b/include/linux/device.h index 68a9535..195b327 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -264,6 +264,10 @@ struct device { struct kobject kobj; char bus_id[BUS_ID_SIZE]; /* position on parent bus */ + struct semaphore sem; /* semaphore to synchronize calls to + * its driver. + */ + struct bus_type * bus; /* type of bus device is on */ struct device_driver *driver; /* which driver has allocated this device */ -- cgit v0.10.2 From 07e4a3e27fe414980ddc85a358e5a56abc48b363 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Mon, 21 Mar 2005 10:52:54 -0800 Subject: [PATCH] Move device/driver code to drivers/base/dd.c This relocates the driver binding/unbinding code to drivers/base/dd.c. This is done for two reasons: One, it's not code related to the bus_type itself; it uses some from that, some from devices, and some from drivers. And Two, it will make it easier to do some of the upcoming lock removal on that code.. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 771f6c8..66d9c46 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -1,6 +1,6 @@ # Makefile for the Linux device tree -obj-y := core.o sys.o bus.o \ +obj-y := core.o sys.o bus.o dd.o \ driver.o class.o platform.o \ cpu.o firmware.o init.o map.o dmapool.o \ attribute_container.o transport_class.o diff --git a/drivers/base/base.h b/drivers/base/base.h index 8d1e8bd..645f6269 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -4,6 +4,8 @@ extern void bus_remove_device(struct device * dev); extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); +extern void driver_detach(struct device_driver * drv); + static inline struct class_device *to_class_dev(struct kobject *obj) { return container_of(obj, struct class_device, kobj); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index aa27f76..1b05c13 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -18,7 +18,6 @@ #include "power/power.h" #define to_dev(node) container_of(node, struct device, bus_list) -#define to_drv(node) container_of(node, struct device_driver, kobj.entry) #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) #define to_bus(obj) container_of(obj, struct bus_type, subsys.kset.kobj) @@ -243,181 +242,6 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, return ret; } -/** - * device_bind_driver - bind a driver to one device. - * @dev: device. - * - * Allow manual attachment of a driver to a device. - * Caller must have already set @dev->driver. - * - * Note that this does not modify the bus reference count - * nor take the bus's rwsem. Please verify those are accounted - * for before calling this. (It is ok to call with no other effort - * from a driver's probe() method.) - */ - -void device_bind_driver(struct device * dev) -{ - pr_debug("bound device '%s' to driver '%s'\n", - dev->bus_id, dev->driver->name); - list_add_tail(&dev->driver_list, &dev->driver->devices); - sysfs_create_link(&dev->driver->kobj, &dev->kobj, - kobject_name(&dev->kobj)); - sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver"); -} - - -/** - * driver_probe_device - attempt to bind device & driver. - * @drv: driver. - * @dev: device. - * - * First, we call the bus's match function, if one present, which - * should compare the device IDs the driver supports with the - * device IDs of the device. Note we don't do this ourselves - * because we don't know the format of the ID structures, nor what - * is to be considered a match and what is not. - * - * If we find a match, we call @drv->probe(@dev) if it exists, and - * call device_bind_driver() above. - */ -int driver_probe_device(struct device_driver * drv, struct device * dev) -{ - int error = 0; - - if (drv->bus->match && !drv->bus->match(dev, drv)) - return -ENODEV; - - down(&dev->sem); - dev->driver = drv; - if (drv->probe) { - error = drv->probe(dev); - if (error) { - dev->driver = NULL; - up(&dev->sem); - return error; - } - } - up(&dev->sem); - device_bind_driver(dev); - return 0; -} - - -/** - * device_attach - try to attach device to a driver. - * @dev: device. - * - * Walk the list of drivers that the bus has and call - * driver_probe_device() for each pair. If a compatible - * pair is found, break out and return. - */ -int device_attach(struct device * dev) -{ - struct bus_type * bus = dev->bus; - struct list_head * entry; - int error; - - if (dev->driver) { - device_bind_driver(dev); - return 1; - } - - if (bus->match) { - list_for_each(entry, &bus->drivers.list) { - struct device_driver * drv = to_drv(entry); - error = driver_probe_device(drv, dev); - if (!error) - /* success, driver matched */ - return 1; - if (error != -ENODEV && error != -ENXIO) - /* driver matched but the probe failed */ - printk(KERN_WARNING - "%s: probe of %s failed with error %d\n", - drv->name, dev->bus_id, error); - } - } - - return 0; -} - - -/** - * driver_attach - try to bind driver to devices. - * @drv: driver. - * - * Walk the list of devices that the bus has on it and try to - * match the driver with each one. If driver_probe_device() - * returns 0 and the @dev->driver is set, we've found a - * compatible pair. - * - * Note that we ignore the -ENODEV error from driver_probe_device(), - * since it's perfectly valid for a driver not to bind to any devices. - */ -void driver_attach(struct device_driver * drv) -{ - struct bus_type * bus = drv->bus; - struct list_head * entry; - int error; - - if (!bus->match) - return; - - list_for_each(entry, &bus->devices.list) { - struct device * dev = container_of(entry, struct device, bus_list); - if (!dev->driver) { - error = driver_probe_device(drv, dev); - if (error && (error != -ENODEV)) - /* driver matched but the probe failed */ - printk(KERN_WARNING - "%s: probe of %s failed with error %d\n", - drv->name, dev->bus_id, error); - } - } -} - - -/** - * device_release_driver - manually detach device from driver. - * @dev: device. - * - * Manually detach device from driver. - * Note that this is called without incrementing the bus - * reference count nor taking the bus's rwsem. Be sure that - * those are accounted for before calling this function. - */ - -void device_release_driver(struct device * dev) -{ - struct device_driver * drv; - - down(&dev->sem); - drv = dev->driver; - if (drv) { - sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); - sysfs_remove_link(&dev->kobj, "driver"); - list_del_init(&dev->driver_list); - if (drv->remove) - drv->remove(dev); - dev->driver = NULL; - } - up(&dev->sem); -} - - -/** - * driver_detach - detach driver from all devices it controls. - * @drv: driver. - */ - -static void driver_detach(struct device_driver * drv) -{ - while (!list_empty(&drv->devices)) { - struct device * dev = container_of(drv->devices.next, struct device, driver_list); - device_release_driver(dev); - } -} - static int device_add_attrs(struct bus_type * bus, struct device * dev) { int error = 0; @@ -757,12 +581,6 @@ int __init buses_init(void) EXPORT_SYMBOL_GPL(bus_for_each_dev); EXPORT_SYMBOL_GPL(bus_for_each_drv); -EXPORT_SYMBOL_GPL(driver_probe_device); -EXPORT_SYMBOL_GPL(device_bind_driver); -EXPORT_SYMBOL_GPL(device_release_driver); -EXPORT_SYMBOL_GPL(device_attach); -EXPORT_SYMBOL_GPL(driver_attach); - EXPORT_SYMBOL_GPL(bus_add_device); EXPORT_SYMBOL_GPL(bus_remove_device); EXPORT_SYMBOL_GPL(bus_register); diff --git a/drivers/base/dd.c b/drivers/base/dd.c new file mode 100644 index 0000000..b709b1e --- /dev/null +++ b/drivers/base/dd.c @@ -0,0 +1,200 @@ +/* + * drivers/base/dd.c - The core device/driver interactions. + * + * This file contains the (sometimes tricky) code that controls the + * interactions between devices and drivers, which primarily includes + * driver binding and unbinding. + * + * All of this code used to exist in drivers/base/bus.c, but was + * relocated to here in the name of compartmentalization (since it wasn't + * strictly code just for the 'struct bus_type'. + * + * Copyright (c) 2002-5 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs + * + * This file is released under the GPLv2 + */ + +#include +#include + +#include "base.h" +#include "power/power.h" + +#define to_drv(node) container_of(node, struct device_driver, kobj.entry) + + +/** + * device_bind_driver - bind a driver to one device. + * @dev: device. + * + * Allow manual attachment of a driver to a device. + * Caller must have already set @dev->driver. + * + * Note that this does not modify the bus reference count + * nor take the bus's rwsem. Please verify those are accounted + * for before calling this. (It is ok to call with no other effort + * from a driver's probe() method.) + */ +void device_bind_driver(struct device * dev) +{ + pr_debug("bound device '%s' to driver '%s'\n", + dev->bus_id, dev->driver->name); + list_add_tail(&dev->driver_list, &dev->driver->devices); + sysfs_create_link(&dev->driver->kobj, &dev->kobj, + kobject_name(&dev->kobj)); + sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver"); +} + +/** + * driver_probe_device - attempt to bind device & driver. + * @drv: driver. + * @dev: device. + * + * First, we call the bus's match function, if one present, which + * should compare the device IDs the driver supports with the + * device IDs of the device. Note we don't do this ourselves + * because we don't know the format of the ID structures, nor what + * is to be considered a match and what is not. + * + * If we find a match, we call @drv->probe(@dev) if it exists, and + * call device_bind_driver() above. + */ +int driver_probe_device(struct device_driver * drv, struct device * dev) +{ + int error = 0; + + if (drv->bus->match && !drv->bus->match(dev, drv)) + return -ENODEV; + + down(&dev->sem); + dev->driver = drv; + if (drv->probe) { + error = drv->probe(dev); + if (error) { + dev->driver = NULL; + up(&dev->sem); + return error; + } + } + up(&dev->sem); + device_bind_driver(dev); + return 0; +} + +/** + * device_attach - try to attach device to a driver. + * @dev: device. + * + * Walk the list of drivers that the bus has and call + * driver_probe_device() for each pair. If a compatible + * pair is found, break out and return. + */ +int device_attach(struct device * dev) +{ + struct bus_type * bus = dev->bus; + struct list_head * entry; + int error; + + if (dev->driver) { + device_bind_driver(dev); + return 1; + } + + if (bus->match) { + list_for_each(entry, &bus->drivers.list) { + struct device_driver * drv = to_drv(entry); + error = driver_probe_device(drv, dev); + if (!error) + /* success, driver matched */ + return 1; + if (error != -ENODEV && error != -ENXIO) + /* driver matched but the probe failed */ + printk(KERN_WARNING + "%s: probe of %s failed with error %d\n", + drv->name, dev->bus_id, error); + } + } + + return 0; +} + +/** + * driver_attach - try to bind driver to devices. + * @drv: driver. + * + * Walk the list of devices that the bus has on it and try to + * match the driver with each one. If driver_probe_device() + * returns 0 and the @dev->driver is set, we've found a + * compatible pair. + * + * Note that we ignore the -ENODEV error from driver_probe_device(), + * since it's perfectly valid for a driver not to bind to any devices. + */ +void driver_attach(struct device_driver * drv) +{ + struct bus_type * bus = drv->bus; + struct list_head * entry; + int error; + + if (!bus->match) + return; + + list_for_each(entry, &bus->devices.list) { + struct device * dev = container_of(entry, struct device, bus_list); + if (!dev->driver) { + error = driver_probe_device(drv, dev); + if (error && (error != -ENODEV)) + /* driver matched but the probe failed */ + printk(KERN_WARNING + "%s: probe of %s failed with error %d\n", + drv->name, dev->bus_id, error); + } + } +} + +/** + * device_release_driver - manually detach device from driver. + * @dev: device. + * + * Manually detach device from driver. + * Note that this is called without incrementing the bus + * reference count nor taking the bus's rwsem. Be sure that + * those are accounted for before calling this function. + */ +void device_release_driver(struct device * dev) +{ + struct device_driver * drv; + + down(&dev->sem); + drv = dev->driver; + if (drv) { + sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); + sysfs_remove_link(&dev->kobj, "driver"); + list_del_init(&dev->driver_list); + if (drv->remove) + drv->remove(dev); + dev->driver = NULL; + } + up(&dev->sem); +} + +/** + * driver_detach - detach driver from all devices it controls. + * @drv: driver. + */ +void driver_detach(struct device_driver * drv) +{ + while (!list_empty(&drv->devices)) { + struct device * dev = container_of(drv->devices.next, struct device, driver_list); + device_release_driver(dev); + } +} + + +EXPORT_SYMBOL_GPL(driver_probe_device); +EXPORT_SYMBOL_GPL(device_bind_driver); +EXPORT_SYMBOL_GPL(device_release_driver); +EXPORT_SYMBOL_GPL(device_attach); +EXPORT_SYMBOL_GPL(driver_attach); + -- cgit v0.10.2 From fae3cd00255e3e51ffd59fedb1bdb91ec96be395 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Mon, 21 Mar 2005 10:59:56 -0800 Subject: [PATCH] Add driver_for_each_device(). Now there's an iterator for accessing each device bound to a driver. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman Index: linux-2.6.12-rc2/drivers/base/driver.c =================================================================== diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 3b269f7..484fed1 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -18,6 +18,41 @@ #define to_dev(node) container_of(node, struct device, driver_list) #define to_drv(obj) container_of(obj, struct device_driver, kobj) + +/** + * driver_for_each_device - Iterator for devices bound to a driver. + * @drv: Driver we're iterating. + * @data: Data to pass to the callback. + * @fn: Function to call for each device. + * + * Take the bus's rwsem and iterate over the @drv's list of devices, + * calling @fn for each one. + */ + +int driver_for_each_device(struct device_driver * drv, struct device * start, + void * data, int (*fn)(struct device *, void *)) +{ + struct list_head * head; + struct device * dev; + int error = 0; + + down_read(&drv->bus->subsys.rwsem); + head = &drv->devices; + dev = list_prepare_entry(start, head, driver_list); + list_for_each_entry_continue(dev, head, driver_list) { + get_device(dev); + error = fn(dev, data); + put_device(dev); + if (error) + break; + } + up_read(&drv->bus->subsys.rwsem); + return error; +} + +EXPORT_SYMBOL(driver_for_each_device); + + /** * driver_create_file - create sysfs file for driver. * @drv: driver. diff --git a/include/linux/device.h b/include/linux/device.h index 195b327..10f5aa20 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -136,6 +136,9 @@ struct driver_attribute driver_attr_##_name = __ATTR(_name,_mode,_show,_store) extern int driver_create_file(struct device_driver *, struct driver_attribute *); extern void driver_remove_file(struct device_driver *, struct driver_attribute *); +extern int driver_for_each_device(struct device_driver * drv, struct device * start, + void * data, int (*fn)(struct device *, void *)); + /* * device classes -- cgit v0.10.2 From 8d618afdd61ccaacbab4976a556c0ddcf36e2d8a Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Mon, 21 Mar 2005 11:07:54 -0800 Subject: [PATCH] Use driver_for_each_device() in drivers/pnp/driver.c instead of manually walking list. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff -Nru a/drivers/pnp/driver.c b/drivers/pnp/driver.c diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index d64c1ca..1d037c2 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -160,10 +160,16 @@ struct bus_type pnp_bus_type = { }; +static int count_devices(struct device * dev, void * c) +{ + int * count = c; + (*count)++; + return 0; +} + int pnp_register_driver(struct pnp_driver *drv) { int count; - struct list_head *pos; pnp_dbg("the driver '%s' has been registered", drv->name); @@ -177,9 +183,7 @@ int pnp_register_driver(struct pnp_driver *drv) /* get the number of initial matches */ if (count >= 0){ count = 0; - list_for_each(pos,&drv->driver.devices){ - count++; - } + driver_for_each_device(&drv->driver, NULL, &count, count_devices); } return count; } -- cgit v0.10.2 From 6034a080f98b0bbc0a058e2ac65a538f75cffeee Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Mon, 21 Mar 2005 11:09:40 -0800 Subject: [PATCH] Use driver_for_each_device() instead of manually walking list. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman Index: gregkh-2.6/drivers/usb/core/usb.c =================================================================== diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 25cf7e9..4453cce 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -462,6 +462,25 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id) return NULL; } + +static int __find_interface(struct device * dev, void * data) +{ + struct usb_interface ** ret = (struct usb_interface **)data; + struct usb_interface * intf = *ret; + int *minor = (int *)data; + + /* can't look at usb devices, only interfaces */ + if (dev->driver == &usb_generic_driver) + return 0; + + intf = to_usb_interface(dev); + if (intf->minor != -1 && intf->minor == *minor) { + *ret = intf; + return 1; + } + return 0; +} + /** * usb_find_interface - find usb_interface pointer for driver and device * @drv: the driver whose current configuration is considered @@ -473,26 +492,12 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id) */ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) { - struct list_head *entry; - struct device *dev; - struct usb_interface *intf; - - list_for_each(entry, &drv->driver.devices) { - dev = container_of(entry, struct device, driver_list); + struct usb_interface *intf = (struct usb_interface *)minor; + int ret; - /* can't look at usb devices, only interfaces */ - if (dev->driver == &usb_generic_driver) - continue; - - intf = to_usb_interface(dev); - if (intf->minor == -1) - continue; - if (intf->minor == minor) - return intf; - } + ret = driver_for_each_device(&drv->driver, NULL, &intf, __find_interface); - /* no device found that matches */ - return NULL; + return ret ? intf : NULL; } static int usb_device_match (struct device *dev, struct device_driver *drv) -- cgit v0.10.2 From 9a19fea43616066561e221359596ce532e631395 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Mon, 21 Mar 2005 11:45:16 -0800 Subject: [PATCH] Add initial implementation of klist helpers. This klist interface provides a couple of structures that wrap around struct list_head to provide explicit list "head" (struct klist) and list "node" (struct klist_node) objects. For struct klist, a spinlock is included that protects access to the actual list itself. struct klist_node provides a pointer to the klist that owns it and a kref reference count that indicates the number of current users of that node in the list. The entire point is to provide an interface for iterating over a list that is safe and allows for modification of the list during the iteration (e.g. insertion and removal), including modification of the current node on the list. It works using a 3rd object type - struct klist_iter - that is declared and initialized before an iteration. klist_next() is used to acquire the next element in the list. It returns NULL if there are no more items. This klist interface provides a couple of structures that wrap around struct list_head to provide explicit list "head" (struct klist) and list "node" (struct klist_node) objects. For struct klist, a spinlock is included that protects access to the actual list itself. struct klist_node provides a pointer to the klist that owns it and a kref reference count that indicates the number of current users of that node in the list. The entire point is to provide an interface for iterating over a list that is safe and allows for modification of the list during the iteration (e.g. insertion and removal), including modification of the current node on the list. It works using a 3rd object type - struct klist_iter - that is declared and initialized before an iteration. klist_next() is used to acquire the next element in the list. It returns NULL if there are no more items. Internally, that routine takes the klist's lock, decrements the reference count of the previous klist_node and increments the count of the next klist_node. It then drops the lock and returns. There are primitives for adding and removing nodes to/from a klist. When deleting, klist_del() will simply decrement the reference count. Only when the count goes to 0 is the node removed from the list. klist_remove() will try to delete the node from the list and block until it is actually removed. This is useful for objects (like devices) that have been removed from the system and must be freed (but must wait until all accessors have finished). Internally, that routine takes the klist's lock, decrements the reference count of the previous klist_node and increments the count of the next klist_node. It then drops the lock and returns. There are primitives for adding and removing nodes to/from a klist. When deleting, klist_del() will simply decrement the reference count. Only when the count goes to 0 is the node removed from the list. klist_remove() will try to delete the node from the list and block until it is actually removed. This is useful for objects (like devices) that have been removed from the system and must be freed (but must wait until all accessors have finished). Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff -Nru a/include/linux/klist.h b/include/linux/klist.h diff --git a/include/linux/klist.h b/include/linux/klist.h new file mode 100644 index 0000000..fb52f9d --- /dev/null +++ b/include/linux/klist.h @@ -0,0 +1,53 @@ +/* + * klist.h - Some generic list helpers, extending struct list_head a bit. + * + * Implementations are found in lib/klist.c + * + * + * Copyright (C) 2005 Patrick Mochel + * + * This file is rleased under the GPL v2. + */ + +#include +#include +#include +#include + + +struct klist { + spinlock_t k_lock; + struct list_head k_list; +}; + + +extern void klist_init(struct klist * k); + + +struct klist_node { + struct klist * n_klist; + struct list_head n_node; + struct kref n_ref; + struct completion n_removed; +}; + +extern void klist_add_tail(struct klist * k, struct klist_node * n); +extern void klist_add_head(struct klist * k, struct klist_node * n); + +extern void klist_del(struct klist_node * n); +extern void klist_remove(struct klist_node * n); + + +struct klist_iter { + struct klist * i_klist; + struct list_head * i_head; + struct klist_node * i_cur; +}; + + +extern void klist_iter_init(struct klist * k, struct klist_iter * i); +extern void klist_iter_init_node(struct klist * k, struct klist_iter * i, + struct klist_node * n); +extern void klist_iter_exit(struct klist_iter * i); +extern struct klist_node * klist_next(struct klist_iter * i); + diff --git a/lib/Makefile b/lib/Makefile index 7c70db7..9eccea9 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -4,9 +4,10 @@ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ - kobject.o kref.o idr.o div64.o int_sqrt.o \ - bitmap.o extable.o kobject_uevent.o prio_tree.o sha1.o \ - halfmd4.o + idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \ + sha1.o halfmd4.o + +lib-y += kobject.o kref.o kobject_uevent.o klist.o obj-y += sort.o parser.o diff --git a/lib/klist.c b/lib/klist.c new file mode 100644 index 0000000..6f76042 --- /dev/null +++ b/lib/klist.c @@ -0,0 +1,248 @@ +/* + * klist.c - Routines for manipulating klists. + * + * + * This klist interface provides a couple of structures that wrap around + * struct list_head to provide explicit list "head" (struct klist) and + * list "node" (struct klist_node) objects. For struct klist, a spinlock + * is included that protects access to the actual list itself. struct + * klist_node provides a pointer to the klist that owns it and a kref + * reference count that indicates the number of current users of that node + * in the list. + * + * The entire point is to provide an interface for iterating over a list + * that is safe and allows for modification of the list during the + * iteration (e.g. insertion and removal), including modification of the + * current node on the list. + * + * It works using a 3rd object type - struct klist_iter - that is declared + * and initialized before an iteration. klist_next() is used to acquire the + * next element in the list. It returns NULL if there are no more items. + * Internally, that routine takes the klist's lock, decrements the reference + * count of the previous klist_node and increments the count of the next + * klist_node. It then drops the lock and returns. + * + * There are primitives for adding and removing nodes to/from a klist. + * When deleting, klist_del() will simply decrement the reference count. + * Only when the count goes to 0 is the node removed from the list. + * klist_remove() will try to delete the node from the list and block + * until it is actually removed. This is useful for objects (like devices) + * that have been removed from the system and must be freed (but must wait + * until all accessors have finished). + * + * Copyright (C) 2005 Patrick Mochel + * + * This file is released under the GPL v2. + */ + +#include +#include + + +/** + * klist_init - Initialize a klist structure. + * @k: The klist we're initializing. + */ + +void klist_init(struct klist * k) +{ + INIT_LIST_HEAD(&k->k_list); + spin_lock_init(&k->k_lock); +} + +EXPORT_SYMBOL_GPL(klist_init); + + +static void add_head(struct klist * k, struct klist_node * n) +{ + spin_lock(&k->k_lock); + list_add(&n->n_node, &k->k_list); + spin_unlock(&k->k_lock); +} + +static void add_tail(struct klist * k, struct klist_node * n) +{ + spin_lock(&k->k_lock); + list_add_tail(&n->n_node, &k->k_list); + spin_unlock(&k->k_lock); +} + + +static void klist_node_init(struct klist * k, struct klist_node * n) +{ + INIT_LIST_HEAD(&n->n_node); + init_completion(&n->n_removed); + kref_init(&n->n_ref); + n->n_klist = k; +} + + +/** + * klist_add_head - Initialize a klist_node and add it to front. + * @k: klist it's going on. + * @n: node we're adding. + */ + +void klist_add_head(struct klist * k, struct klist_node * n) +{ + klist_node_init(k, n); + add_head(k, n); +} + +EXPORT_SYMBOL_GPL(klist_add_head); + + +/** + * klist_add_tail - Initialize a klist_node and add it to back. + * @k: klist it's going on. + * @n: node we're adding. + */ + +void klist_add_tail(struct klist * k, struct klist_node * n) +{ + klist_node_init(k, n); + add_tail(k, n); +} + +EXPORT_SYMBOL_GPL(klist_add_tail); + + +static void klist_release(struct kref * kref) +{ + struct klist_node * n = container_of(kref, struct klist_node, n_ref); + list_del(&n->n_node); + complete(&n->n_removed); +} + +static int klist_dec_and_del(struct klist_node * n) +{ + return kref_put(&n->n_ref, klist_release); +} + + +/** + * klist_del - Decrement the reference count of node and try to remove. + * @n: node we're deleting. + */ + +void klist_del(struct klist_node * n) +{ + struct klist * k = n->n_klist; + + spin_lock(&k->k_lock); + klist_dec_and_del(n); + spin_unlock(&k->k_lock); +} + +EXPORT_SYMBOL_GPL(klist_del); + + +/** + * klist_remove - Decrement the refcount of node and wait for it to go away. + * @n: node we're removing. + */ + +void klist_remove(struct klist_node * n) +{ + spin_lock(&n->n_klist->k_lock); + klist_dec_and_del(n); + spin_unlock(&n->n_klist->k_lock); + wait_for_completion(&n->n_removed); +} + +EXPORT_SYMBOL_GPL(klist_remove); + + +/** + * klist_iter_init_node - Initialize a klist_iter structure. + * @k: klist we're iterating. + * @i: klist_iter we're filling. + * @n: node to start with. + * + * Similar to klist_iter_init(), but starts the action off with @n, + * instead of with the list head. + */ + +void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_node * n) +{ + i->i_klist = k; + i->i_head = &k->k_list; + i->i_cur = n; +} + +EXPORT_SYMBOL_GPL(klist_iter_init_node); + + +/** + * klist_iter_init - Iniitalize a klist_iter structure. + * @k: klist we're iterating. + * @i: klist_iter structure we're filling. + * + * Similar to klist_iter_init_node(), but start with the list head. + */ + +void klist_iter_init(struct klist * k, struct klist_iter * i) +{ + klist_iter_init_node(k, i, NULL); +} + +EXPORT_SYMBOL_GPL(klist_iter_init); + + +/** + * klist_iter_exit - Finish a list iteration. + * @i: Iterator structure. + * + * Must be called when done iterating over list, as it decrements the + * refcount of the current node. Necessary in case iteration exited before + * the end of the list was reached, and always good form. + */ + +void klist_iter_exit(struct klist_iter * i) +{ + if (i->i_cur) { + klist_del(i->i_cur); + i->i_cur = NULL; + } +} + +EXPORT_SYMBOL_GPL(klist_iter_exit); + + +static struct klist_node * to_klist_node(struct list_head * n) +{ + return container_of(n, struct klist_node, n_node); +} + + +/** + * klist_next - Ante up next node in list. + * @i: Iterator structure. + * + * First grab list lock. Decrement the reference count of the previous + * node, if there was one. Grab the next node, increment its reference + * count, drop the lock, and return that next node. + */ + +struct klist_node * klist_next(struct klist_iter * i) +{ + struct list_head * next; + struct klist_node * knode = NULL; + + spin_lock(&i->i_klist->k_lock); + if (i->i_cur) { + next = i->i_cur->n_node.next; + klist_dec_and_del(i->i_cur); + } else + next = i->i_head->next; + + if (next != i->i_head) { + knode = to_klist_node(next); + kref_get(&knode->n_ref); + } + i->i_cur = knode; + spin_unlock(&i->i_klist->k_lock); + return knode; +} + +EXPORT_SYMBOL_GPL(klist_next); -- cgit v0.10.2 From 465c7a3a3a5aabcedd2e43612cac5a12f23da19a Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Mon, 21 Mar 2005 11:49:14 -0800 Subject: [PATCH] Add a klist to struct bus_type for its devices. - Use it for bus_for_each_dev(). - Use the klist spinlock instead of the bus rwsem. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 1b05c13..c8da372 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -134,28 +134,6 @@ static struct kobj_type ktype_bus = { decl_subsys(bus, &ktype_bus, NULL); -static int __bus_for_each_dev(struct bus_type *bus, struct device *start, - void *data, int (*fn)(struct device *, void *)) -{ - struct list_head *head; - struct device *dev; - int error = 0; - - if (!(bus = get_bus(bus))) - return -EINVAL; - - head = &bus->devices.list; - dev = list_prepare_entry(start, head, bus_list); - list_for_each_entry_continue(dev, head, bus_list) { - get_device(dev); - error = fn(dev, data); - put_device(dev); - if (error) - break; - } - put_bus(bus); - return error; -} static int __bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void * data, int (*fn)(struct device_driver *, void *)) @@ -180,6 +158,13 @@ static int __bus_for_each_drv(struct bus_type *bus, struct device_driver *start, return error; } + +static struct device * next_device(struct klist_iter * i) +{ + struct klist_node * n = klist_next(i); + return n ? container_of(n, struct device, knode_bus) : NULL; +} + /** * bus_for_each_dev - device iterator. * @bus: bus type. @@ -203,12 +188,19 @@ static int __bus_for_each_drv(struct bus_type *bus, struct device_driver *start, int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, int (*fn)(struct device *, void *)) { - int ret; + struct klist_iter i; + struct device * dev; + int error = 0; - down_read(&bus->subsys.rwsem); - ret = __bus_for_each_dev(bus, start, data, fn); - up_read(&bus->subsys.rwsem); - return ret; + if (!bus) + return -EINVAL; + + klist_iter_init_node(&bus->klist_devices, &i, + (start ? &start->knode_bus : NULL)); + while ((dev = next_device(&i)) && !error) + error = fn(dev, data); + klist_iter_exit(&i); + return error; } /** @@ -293,6 +285,7 @@ int bus_add_device(struct device * dev) list_add_tail(&dev->bus_list, &dev->bus->devices.list); device_attach(dev); up_write(&dev->bus->subsys.rwsem); + klist_add_tail(&bus->klist_devices, &dev->knode_bus); device_add_attrs(bus, dev); sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus"); @@ -315,6 +308,7 @@ void bus_remove_device(struct device * dev) sysfs_remove_link(&dev->kobj, "bus"); sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); device_remove_attrs(dev->bus, dev); + klist_remove(&dev->knode_bus); down_write(&dev->bus->subsys.rwsem); pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); @@ -439,9 +433,7 @@ int bus_rescan_devices(struct bus_type * bus) { int count = 0; - down_write(&bus->subsys.rwsem); - __bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper); - up_write(&bus->subsys.rwsem); + bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper); return count; } @@ -542,6 +534,8 @@ int bus_register(struct bus_type * bus) retval = kset_register(&bus->drivers); if (retval) goto bus_drivers_fail; + + klist_init(&bus->klist_devices); bus_add_attrs(bus); pr_debug("bus type '%s' registered\n", bus->name); diff --git a/include/linux/device.h b/include/linux/device.h index 10f5aa20..e36953c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ struct bus_type { struct subsystem subsys; struct kset drivers; struct kset devices; + struct klist klist_devices; struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; @@ -262,6 +264,7 @@ struct device { struct list_head bus_list; /* node in bus's list */ struct list_head driver_list; struct list_head children; + struct klist_node knode_bus; struct device * parent; struct kobject kobj; -- cgit v0.10.2 From 38fdac3cdce276554b4484a41f8ec2daf81cb2ff Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Mon, 21 Mar 2005 12:00:18 -0800 Subject: [PATCH] Add a klist to struct bus_type for its drivers. - Use it in bus_for_each_drv(). - Use the klist spinlock instead of the bus rwsem. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index c8da372..736dc1f 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -135,30 +135,6 @@ static struct kobj_type ktype_bus = { decl_subsys(bus, &ktype_bus, NULL); -static int __bus_for_each_drv(struct bus_type *bus, struct device_driver *start, - void * data, int (*fn)(struct device_driver *, void *)) -{ - struct list_head *head; - struct device_driver *drv; - int error = 0; - - if (!(bus = get_bus(bus))) - return -EINVAL; - - head = &bus->drivers.list; - drv = list_prepare_entry(start, head, kobj.entry); - list_for_each_entry_continue(drv, head, kobj.entry) { - get_driver(drv); - error = fn(drv, data); - put_driver(drv); - if (error) - break; - } - put_bus(bus); - return error; -} - - static struct device * next_device(struct klist_iter * i) { struct klist_node * n = klist_next(i); @@ -203,6 +179,14 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start, return error; } + + +static struct device_driver * next_driver(struct klist_iter * i) +{ + struct klist_node * n = klist_next(i); + return n ? container_of(n, struct device_driver, knode_bus) : NULL; +} + /** * bus_for_each_drv - driver iterator * @bus: bus we're dealing with. @@ -226,12 +210,19 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start, int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, void * data, int (*fn)(struct device_driver *, void *)) { - int ret; + struct klist_iter i; + struct device_driver * drv; + int error = 0; - down_read(&bus->subsys.rwsem); - ret = __bus_for_each_drv(bus, start, data, fn); - up_read(&bus->subsys.rwsem); - return ret; + if (!bus) + return -EINVAL; + + klist_iter_init_node(&bus->klist_drivers, &i, + start ? &start->knode_bus : NULL); + while ((drv = next_driver(&i)) && !error) + error = fn(drv, data); + klist_iter_exit(&i); + return error; } static int device_add_attrs(struct bus_type * bus, struct device * dev) @@ -376,6 +367,7 @@ int bus_add_driver(struct device_driver * drv) down_write(&bus->subsys.rwsem); driver_attach(drv); up_write(&bus->subsys.rwsem); + klist_add_tail(&bus->klist_drivers, &drv->knode_bus); module_add_driver(drv->owner, drv); driver_add_attrs(bus, drv); @@ -397,6 +389,7 @@ void bus_remove_driver(struct device_driver * drv) { if (drv->bus) { driver_remove_attrs(drv->bus, drv); + klist_remove(&drv->knode_bus); down_write(&drv->bus->subsys.rwsem); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); @@ -536,6 +529,7 @@ int bus_register(struct bus_type * bus) goto bus_drivers_fail; klist_init(&bus->klist_devices); + klist_init(&bus->klist_drivers); bus_add_attrs(bus); pr_debug("bus type '%s' registered\n", bus->name); diff --git a/include/linux/device.h b/include/linux/device.h index e36953c..ea9ab33 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -53,6 +53,7 @@ struct bus_type { struct kset drivers; struct kset devices; struct klist klist_devices; + struct klist klist_drivers; struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; @@ -105,6 +106,7 @@ struct device_driver { struct completion unloaded; struct kobject kobj; struct list_head devices; + struct klist_node knode_bus; struct module * owner; -- cgit v0.10.2 From 94e7b1c5ff2055571703e38b059afffe17658432 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Mon, 21 Mar 2005 12:25:36 -0800 Subject: [PATCH] Add a klist to struct device_driver for the devices bound to it. - Use it in driver_for_each_device() instead of the regular list_head and stop using the bus's rwsem for protection. - Use driver_for_each_device() in driver_detach() so we don't deadlock on the bus's rwsem. - Remove ->devices. - Move klist access and sysfs link access out from under device's semaphore, since they're synchronized through other means. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/core.c b/drivers/base/core.c index 9344082..bc5bec6 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -209,8 +209,8 @@ void device_initialize(struct device *dev) kobject_init(&dev->kobj); INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->children); - INIT_LIST_HEAD(&dev->driver_list); INIT_LIST_HEAD(&dev->bus_list); + INIT_LIST_HEAD(&dev->driver_list); INIT_LIST_HEAD(&dev->dma_pools); init_MUTEX(&dev->sem); } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index b709b1e..47cbb56 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -40,7 +40,7 @@ void device_bind_driver(struct device * dev) { pr_debug("bound device '%s' to driver '%s'\n", dev->bus_id, dev->driver->name); - list_add_tail(&dev->driver_list, &dev->driver->devices); + klist_add_tail(&dev->driver->klist_devices, &dev->knode_driver); sysfs_create_link(&dev->driver->kobj, &dev->kobj, kobject_name(&dev->kobj)); sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver"); @@ -164,31 +164,35 @@ void driver_attach(struct device_driver * drv) */ void device_release_driver(struct device * dev) { - struct device_driver * drv; + struct device_driver * drv = dev->driver; + + if (!drv) + return; + + sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); + sysfs_remove_link(&dev->kobj, "driver"); + klist_remove(&dev->knode_driver); down(&dev->sem); - drv = dev->driver; - if (drv) { - sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); - sysfs_remove_link(&dev->kobj, "driver"); - list_del_init(&dev->driver_list); - if (drv->remove) - drv->remove(dev); - dev->driver = NULL; - } + if (drv->remove) + drv->remove(dev); + dev->driver = NULL; up(&dev->sem); } +static int __remove_driver(struct device * dev, void * unused) +{ + device_release_driver(dev); + return 0; +} + /** * driver_detach - detach driver from all devices it controls. * @drv: driver. */ void driver_detach(struct device_driver * drv) { - while (!list_empty(&drv->devices)) { - struct device * dev = container_of(drv->devices.next, struct device, driver_list); - device_release_driver(dev); - } + driver_for_each_device(drv, NULL, NULL, __remove_driver); } diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 484fed1..34bd38a 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -19,6 +19,12 @@ #define to_drv(obj) container_of(obj, struct device_driver, kobj) +static struct device * next_device(struct klist_iter * i) +{ + struct klist_node * n = klist_next(i); + return n ? container_of(n, struct device, knode_driver) : NULL; +} + /** * driver_for_each_device - Iterator for devices bound to a driver. * @drv: Driver we're iterating. @@ -32,21 +38,18 @@ int driver_for_each_device(struct device_driver * drv, struct device * start, void * data, int (*fn)(struct device *, void *)) { - struct list_head * head; + struct klist_iter i; struct device * dev; int error = 0; - down_read(&drv->bus->subsys.rwsem); - head = &drv->devices; - dev = list_prepare_entry(start, head, driver_list); - list_for_each_entry_continue(dev, head, driver_list) { - get_device(dev); + if (!drv) + return -EINVAL; + + klist_iter_init_node(&drv->klist_devices, &i, + start ? &start->knode_driver : NULL); + while ((dev = next_device(&i)) && !error) error = fn(dev, data); - put_device(dev); - if (error) - break; - } - up_read(&drv->bus->subsys.rwsem); + klist_iter_exit(&i); return error; } @@ -120,7 +123,7 @@ void put_driver(struct device_driver * drv) */ int driver_register(struct device_driver * drv) { - INIT_LIST_HEAD(&drv->devices); + klist_init(&drv->klist_devices); init_completion(&drv->unloaded); return bus_add_driver(drv); } diff --git a/include/linux/device.h b/include/linux/device.h index ea9ab33..96c71b5 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -105,7 +105,7 @@ struct device_driver { struct completion unloaded; struct kobject kobj; - struct list_head devices; + struct klist klist_devices; struct klist_node knode_bus; struct module * owner; @@ -266,6 +266,7 @@ struct device { struct list_head bus_list; /* node in bus's list */ struct list_head driver_list; struct list_head children; + struct klist_node knode_driver; struct klist_node knode_bus; struct device * parent; -- cgit v0.10.2 From cb85b6f1cc811ecb9ed4b950206d8941ba710e68 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 10:48:35 -0800 Subject: [PATCH] Remove the unused device_find(). Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/core.c b/drivers/base/core.c index bc5bec6..0eb1d42 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -401,24 +401,6 @@ int device_for_each_child(struct device * dev, void * data, return error; } -/** - * device_find - locate device on a bus by name. - * @name: name of the device. - * @bus: bus to scan for the device. - * - * Call kset_find_obj() to iterate over list of devices on - * a bus to find device by name. Return device if found. - * - * Note that kset_find_obj increments device's reference count. - */ -struct device *device_find(const char *name, struct bus_type *bus) -{ - struct kobject *k = kset_find_obj(&bus->devices, name); - if (k) - return to_dev(k); - return NULL; -} - int __init devices_init(void) { return subsystem_register(&devices_subsys); @@ -434,7 +416,6 @@ EXPORT_SYMBOL_GPL(device_del); EXPORT_SYMBOL_GPL(device_unregister); EXPORT_SYMBOL_GPL(get_device); EXPORT_SYMBOL_GPL(put_device); -EXPORT_SYMBOL_GPL(device_find); EXPORT_SYMBOL_GPL(device_create_file); EXPORT_SYMBOL_GPL(device_remove_file); diff --git a/include/linux/device.h b/include/linux/device.h index 96c71b5..f1c38d8 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -372,7 +372,6 @@ extern int (*platform_notify_remove)(struct device * dev); */ extern struct device * get_device(struct device * dev); extern void put_device(struct device * dev); -extern struct device *device_find(const char *name, struct bus_type *bus); /* drivers/base/platform.c */ -- cgit v0.10.2 From 2287c322b61fced7e0c326a1a9606aa73147e3df Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 10:50:24 -0800 Subject: [PATCH] Use bus_for_each_{dev,drv} for driver binding. - Now possible, since the lists are locked using the klist lock and not the global rwsem. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 47cbb56..85042ad 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -82,6 +82,28 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) return 0; } +static int __device_attach(struct device_driver * drv, void * data) +{ + struct device * dev = data; + int error; + + error = driver_probe_device(drv, dev); + + if (error == -ENODEV && error == -ENXIO) { + /* Driver matched, but didn't support device + * or device not found. + * Not an error; keep going. + */ + error = 0; + } else { + /* driver matched but the probe failed */ + printk(KERN_WARNING + "%s: probe of %s failed with error %d\n", + drv->name, dev->bus_id, error); + } + return 0; +} + /** * device_attach - try to attach device to a driver. * @dev: device. @@ -92,30 +114,31 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) */ int device_attach(struct device * dev) { - struct bus_type * bus = dev->bus; - struct list_head * entry; - int error; - if (dev->driver) { device_bind_driver(dev); return 1; } - if (bus->match) { - list_for_each(entry, &bus->drivers.list) { - struct device_driver * drv = to_drv(entry); - error = driver_probe_device(drv, dev); - if (!error) - /* success, driver matched */ - return 1; - if (error != -ENODEV && error != -ENXIO) + return bus_for_each_drv(dev->bus, NULL, dev, __device_attach); +} + +static int __driver_attach(struct device * dev, void * data) +{ + struct device_driver * drv = data; + int error = 0; + + if (!dev->driver) { + error = driver_probe_device(drv, dev); + if (error) { + if (error != -ENODEV) { /* driver matched but the probe failed */ printk(KERN_WARNING - "%s: probe of %s failed with error %d\n", - drv->name, dev->bus_id, error); + "%s: probe of %s failed with error %d\n", + drv->name, dev->bus_id, error); + } else + error = 0; } } - return 0; } @@ -133,24 +156,7 @@ int device_attach(struct device * dev) */ void driver_attach(struct device_driver * drv) { - struct bus_type * bus = drv->bus; - struct list_head * entry; - int error; - - if (!bus->match) - return; - - list_for_each(entry, &bus->devices.list) { - struct device * dev = container_of(entry, struct device, bus_list); - if (!dev->driver) { - error = driver_probe_device(drv, dev); - if (error && (error != -ENODEV)) - /* driver matched but the probe failed */ - printk(KERN_WARNING - "%s: probe of %s failed with error %d\n", - drv->name, dev->bus_id, error); - } - } + bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); } /** -- cgit v0.10.2 From 8b0c250be489dcbf1a3a33bb4ec4c7f33735a365 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 12:58:57 -0800 Subject: [PATCH] add klist_node_attached() to determine if a node is on a list or not. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff -Nru a/include/linux/klist.h b/include/linux/klist.h diff --git a/include/linux/klist.h b/include/linux/klist.h index fb52f9d..eebf5e5 100644 --- a/include/linux/klist.h +++ b/include/linux/klist.h @@ -37,6 +37,8 @@ extern void klist_add_head(struct klist * k, struct klist_node * n); extern void klist_del(struct klist_node * n); extern void klist_remove(struct klist_node * n); +extern int klist_node_attached(struct klist_node * n); + struct klist_iter { struct klist * i_klist; diff --git a/lib/klist.c b/lib/klist.c index 6f76042..02177d7 100644 --- a/lib/klist.c +++ b/lib/klist.c @@ -112,6 +112,7 @@ static void klist_release(struct kref * kref) struct klist_node * n = container_of(kref, struct klist_node, n_ref); list_del(&n->n_node); complete(&n->n_removed); + n->n_klist = NULL; } static int klist_dec_and_del(struct klist_node * n) @@ -154,6 +155,19 @@ EXPORT_SYMBOL_GPL(klist_remove); /** + * klist_node_attached - Say whether a node is bound to a list or not. + * @n: Node that we're testing. + */ + +int klist_node_attached(struct klist_node * n) +{ + return (n->n_klist != NULL); +} + +EXPORT_SYMBOL_GPL(klist_node_attached); + + +/** * klist_iter_init_node - Initialize a klist_iter structure. * @k: klist we're iterating. * @i: klist_iter we're filling. @@ -246,3 +260,5 @@ struct klist_node * klist_next(struct klist_iter * i) } EXPORT_SYMBOL_GPL(klist_next); + + -- cgit v0.10.2 From d4a7537122fa47a6ce41c5fdab53d844c78d7023 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 13:00:16 -0800 Subject: [PATCH] Fix up USB to use klist_node_attached() instead of list_empty() on lists that will go away. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman Index: gregkh-2.6/drivers/usb/core/usb.c =================================================================== diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4453cce..a649743 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -293,7 +293,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() */ - if (!list_empty (&dev->bus_list)) + if (!klist_node_attached (&dev->knode_bus)) device_bind_driver(dev); return 0; @@ -323,7 +323,7 @@ void usb_driver_release_interface(struct usb_driver *driver, return; /* don't disconnect from disconnect(), or before dev_add() */ - if (!list_empty (&dev->driver_list) && !list_empty (&dev->bus_list)) + if (!klist_node_attached(&dev->knode_driver) && !klist_node_attached(&dev->knode_bus)) device_release_driver(dev); dev->driver = NULL; -- cgit v0.10.2 From 6eded061b1263847aedac7469339e99579aec5e5 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 13:02:28 -0800 Subject: [PATCH] Fix up bus code and remove use of rwsem. - Don't add devices to bus's embedded kset, since it's not used by anyone anymore. - Don't need to take the bus rwsem when calling {device,driver}_attach(), since those functions use the klists and the klists' spinlocks. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 736dc1f..4eb1952 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -17,8 +17,6 @@ #include "base.h" #include "power/power.h" -#define to_dev(node) container_of(node, struct device, bus_list) - #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) #define to_bus(obj) container_of(obj, struct bus_type, subsys.kset.kobj) @@ -271,11 +269,8 @@ int bus_add_device(struct device * dev) int error = 0; if (bus) { - down_write(&dev->bus->subsys.rwsem); pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); - list_add_tail(&dev->bus_list, &dev->bus->devices.list); device_attach(dev); - up_write(&dev->bus->subsys.rwsem); klist_add_tail(&bus->klist_devices, &dev->knode_bus); device_add_attrs(bus, dev); sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); @@ -300,11 +295,8 @@ void bus_remove_device(struct device * dev) sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); device_remove_attrs(dev->bus, dev); klist_remove(&dev->knode_bus); - down_write(&dev->bus->subsys.rwsem); pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); - list_del_init(&dev->bus_list); - up_write(&dev->bus->subsys.rwsem); put_bus(dev->bus); } } @@ -364,9 +356,7 @@ int bus_add_driver(struct device_driver * drv) return error; } - down_write(&bus->subsys.rwsem); driver_attach(drv); - up_write(&bus->subsys.rwsem); klist_add_tail(&bus->klist_drivers, &drv->knode_bus); module_add_driver(drv->owner, drv); @@ -390,10 +380,8 @@ void bus_remove_driver(struct device_driver * drv) if (drv->bus) { driver_remove_attrs(drv->bus, drv); klist_remove(&drv->knode_bus); - down_write(&drv->bus->subsys.rwsem); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); - up_write(&drv->bus->subsys.rwsem); module_remove_driver(drv); kobject_unregister(&drv->kobj); put_bus(drv->bus); -- cgit v0.10.2 From 7dc35cdf69149a7f2b5216ada9bafe359746ac1c Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 13:03:35 -0800 Subject: [PATCH] Remove struct device::bus_list. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/core.c b/drivers/base/core.c index 0eb1d42..f258a21 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -209,7 +209,6 @@ void device_initialize(struct device *dev) kobject_init(&dev->kobj); INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->children); - INIT_LIST_HEAD(&dev->bus_list); INIT_LIST_HEAD(&dev->driver_list); INIT_LIST_HEAD(&dev->dma_pools); init_MUTEX(&dev->sem); diff --git a/include/linux/device.h b/include/linux/device.h index f1c38d8..13f6585 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -263,7 +263,6 @@ extern void class_device_destroy(struct class *cls, dev_t devt); struct device { struct list_head node; /* node in sibling list */ - struct list_head bus_list; /* node in bus's list */ struct list_head driver_list; struct list_head children; struct klist_node knode_driver; -- cgit v0.10.2 From 63c4f204ffc8219696bda88eb20c9873d007a2fc Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 13:08:05 -0800 Subject: [PATCH] Remove struct device::driver_list. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/core.c b/drivers/base/core.c index f258a21..bfa4268 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -209,7 +209,6 @@ void device_initialize(struct device *dev) kobject_init(&dev->kobj); INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->children); - INIT_LIST_HEAD(&dev->driver_list); INIT_LIST_HEAD(&dev->dma_pools); init_MUTEX(&dev->sem); } diff --git a/include/linux/device.h b/include/linux/device.h index 13f6585..d243493 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -263,7 +263,6 @@ extern void class_device_destroy(struct class *cls, dev_t devt); struct device { struct list_head node; /* node in sibling list */ - struct list_head driver_list; struct list_head children; struct klist_node knode_driver; struct klist_node knode_bus; -- cgit v0.10.2 From 0956af53afea290c5676c75249fc2c180d831375 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 18:58:45 -0800 Subject: [PATCH] Call klist_del() instead of klist_remove(). - Can't wait on removing the current item in the list (the positive refcount *because* we are using it causes it to deadlock). Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 85042ad..159e062 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -177,7 +177,7 @@ void device_release_driver(struct device * dev) sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&dev->kobj, "driver"); - klist_remove(&dev->knode_driver); + klist_del(&dev->knode_driver); down(&dev->sem); if (drv->remove) -- cgit v0.10.2 From 0293a509405dccecc30783a5d729d615b68d6a77 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 18:59:59 -0800 Subject: [PATCH] Don't reference NULL klist pointer in klist_remove(). Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff -Nru a/lib/klist.c b/lib/klist.c diff --git a/lib/klist.c b/lib/klist.c index 02177d7..738ab81 100644 --- a/lib/klist.c +++ b/lib/klist.c @@ -145,9 +145,10 @@ EXPORT_SYMBOL_GPL(klist_del); void klist_remove(struct klist_node * n) { - spin_lock(&n->n_klist->k_lock); + struct klist * k = n->n_klist; + spin_lock(&k->k_lock); klist_dec_and_del(n); - spin_unlock(&n->n_klist->k_lock); + spin_unlock(&k->k_lock); wait_for_completion(&n->n_removed); } -- cgit v0.10.2 From 20b1e674230b642be662c5975923a0160ab9cbdc Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 19:03:59 -0800 Subject: [PATCH] Use device_for_each_child() to unregister devices in scsi_remove_target(). Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman Index: gregkh-2.6/drivers/scsi/scsi_sysfs.c =================================================================== diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index e75ee46..7134618 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -669,6 +669,13 @@ void __scsi_remove_target(struct scsi_target *starget) scsi_target_reap(starget); } +static int __remove_child (struct device * dev, void * data) +{ + if (scsi_is_target_device(dev)) + __scsi_remove_target(to_scsi_target(dev)); + return 0; +} + /** * scsi_remove_target - try to remove a target and all its devices * @dev: generic starget or parent of generic stargets to be removed @@ -679,7 +686,7 @@ void __scsi_remove_target(struct scsi_target *starget) */ void scsi_remove_target(struct device *dev) { - struct device *rdev, *idev, *next; + struct device *rdev; if (scsi_is_target_device(dev)) { __scsi_remove_target(to_scsi_target(dev)); @@ -687,10 +694,7 @@ void scsi_remove_target(struct device *dev) } rdev = get_device(dev); - list_for_each_entry_safe(idev, next, &dev->children, node) { - if (scsi_is_target_device(idev)) - __scsi_remove_target(to_scsi_target(idev)); - } + device_for_each_child(dev, NULL, __remove_child); put_device(rdev); } EXPORT_SYMBOL(scsi_remove_target); -- cgit v0.10.2 From 9a881f166f473373589ce6f3fdc47b44a1450e2d Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Fri, 25 Mar 2005 15:52:00 -0800 Subject: [PATCH] use device_for_each_child() to properly access child devices. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index c87ae46..2918b96 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -348,17 +348,21 @@ spi_transport_rd_attr(rd_strm, "%d\n"); spi_transport_rd_attr(rti, "%d\n"); spi_transport_rd_attr(pcomp_en, "%d\n"); +/* we only care about the first child device so we return 1 */ +static int child_iter(struct device *dev, void *data) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + spi_dv_device(sdev); + return 1; +} + static ssize_t store_spi_revalidate(struct class_device *cdev, const char *buf, size_t count) { struct scsi_target *starget = transport_class_to_starget(cdev); - /* FIXME: we're relying on an awful lot of device internals - * here. We really need a function to get the first available - * child */ - struct device *dev = container_of(starget->dev.children.next, struct device, node); - struct scsi_device *sdev = to_scsi_device(dev); - spi_dv_device(sdev); + device_for_each_child(&starget->dev, NULL, child_iter); return count; } static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate); -- cgit v0.10.2 From 36239577cfb6b9a7c111209536b54200b0252ebf Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 19:08:30 -0800 Subject: [PATCH] Use a klist for device child lists. - Use klist iterator in device_for_each_child(), making it safe to use for removing devices. - Remove unused list_to_dev() function. - Kills all usage of devices_subsys.rwsem. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/core.c b/drivers/base/core.c index bfa4268..1d8c779 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -207,8 +207,7 @@ void device_initialize(struct device *dev) { kobj_set_kset_s(dev, devices_subsys); kobject_init(&dev->kobj); - INIT_LIST_HEAD(&dev->node); - INIT_LIST_HEAD(&dev->children); + klist_init(&dev->klist_children); INIT_LIST_HEAD(&dev->dma_pools); init_MUTEX(&dev->sem); } @@ -249,10 +248,8 @@ int device_add(struct device *dev) goto PMError; if ((error = bus_add_device(dev))) goto BusError; - down_write(&devices_subsys.rwsem); if (parent) - list_add_tail(&dev->node, &parent->children); - up_write(&devices_subsys.rwsem); + klist_add_tail(&parent->klist_children, &dev->knode_parent); /* notify platform of device entry */ if (platform_notify) @@ -335,10 +332,8 @@ void device_del(struct device * dev) { struct device * parent = dev->parent; - down_write(&devices_subsys.rwsem); if (parent) - list_del_init(&dev->node); - up_write(&devices_subsys.rwsem); + klist_remove(&dev->knode_parent); /* Notify the platform of the removal, in case they * need to do anything... @@ -372,6 +367,12 @@ void device_unregister(struct device * dev) } +static struct device * next_device(struct klist_iter * i) +{ + struct klist_node * n = klist_next(i); + return n ? container_of(n, struct device, knode_parent) : NULL; +} + /** * device_for_each_child - device child iterator. * @dev: parent struct device. @@ -384,18 +385,17 @@ void device_unregister(struct device * dev) * We check the return of @fn each time. If it returns anything * other than 0, we break out and return that value. */ -int device_for_each_child(struct device * dev, void * data, +int device_for_each_child(struct device * parent, void * data, int (*fn)(struct device *, void *)) { + struct klist_iter i; struct device * child; int error = 0; - down_read(&devices_subsys.rwsem); - list_for_each_entry(child, &dev->children, node) { - if((error = fn(child, data))) - break; - } - up_read(&devices_subsys.rwsem); + klist_iter_init(&parent->klist_children, &i); + while ((child = next_device(&i)) && !error) + error = fn(child, data); + klist_iter_exit(&i); return error; } diff --git a/include/linux/device.h b/include/linux/device.h index d243493..4324926 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -262,8 +262,8 @@ extern void class_device_destroy(struct class *cls, dev_t devt); struct device { - struct list_head node; /* node in sibling list */ - struct list_head children; + struct klist klist_children; + struct klist_node knode_parent; /* node in sibling list */ struct klist_node knode_driver; struct klist_node knode_bus; struct device * parent; @@ -298,12 +298,6 @@ struct device { void (*release)(struct device * dev); }; -static inline struct device * -list_to_dev(struct list_head *node) -{ - return list_entry(node, struct device, node); -} - static inline void * dev_get_drvdata (struct device *dev) { -- cgit v0.10.2 From 4d12d2d953ca5e299de6a653f1d0478f670d7bc6 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 20:08:04 -0800 Subject: [PATCH] Fix up bogus comment. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 34bd38a..f789b6c 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -31,8 +31,7 @@ static struct device * next_device(struct klist_iter * i) * @data: Data to pass to the callback. * @fn: Function to call for each device. * - * Take the bus's rwsem and iterate over the @drv's list of devices, - * calling @fn for each one. + * Iterate over the @drv's list of devices calling @fn for each one. */ int driver_for_each_device(struct device_driver * drv, struct device * start, -- cgit v0.10.2 From 126eddfbf8cae8a20c22708192bffcbd77c8a889 Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Tue, 22 Mar 2005 12:17:13 -0800 Subject: [PATCH] driver core: change export symbol for driver_for_each_device() Signed-off-by: Greg Kroah-Hartman Index: linux-2.6.12-rc2/drivers/base/driver.c =================================================================== diff --git a/drivers/base/driver.c b/drivers/base/driver.c index f789b6c..1b64588 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -52,7 +52,7 @@ int driver_for_each_device(struct device_driver * drv, struct device * start, return error; } -EXPORT_SYMBOL(driver_for_each_device); +EXPORT_SYMBOL_GPL(driver_for_each_device); /** -- cgit v0.10.2 From ff710710eae73990dd484ea8e37dba636452502b Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Thu, 24 Mar 2005 00:44:28 -0800 Subject: [PATCH] USB: fix build warning in usb core as pointed out by Andrew. Signed-off-by: Greg Kroah-Hartman Index: gregkh-2.6/drivers/usb/core/usb.c =================================================================== diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index a649743..230839a 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -492,7 +492,7 @@ static int __find_interface(struct device * dev, void * data) */ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) { - struct usb_interface *intf = (struct usb_interface *)minor; + struct usb_interface *intf = (struct usb_interface *)(long)minor; int ret; ret = driver_for_each_device(&drv->driver, NULL, &intf, __find_interface); -- cgit v0.10.2 From 64360322ab3330d4881166380ad43a1eec2f123d Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Fri, 25 Mar 2005 11:45:31 -0800 Subject: [PATCH] Use device_for_each_child() to unregister devices in nodemgr_remove_host_dev() Signed-off-by: Greg Kroah-Hartman diff -Nru a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 83e66ed..a155b39 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -695,14 +695,15 @@ static void nodemgr_remove_ne(struct node_entry *ne) put_device(dev); } +static int __nodemgr_remove_host_dev(struct device *dev, void *data) +{ + nodemgr_remove_ne(container_of(dev, struct node_entry, device)); + return 0; +} static void nodemgr_remove_host_dev(struct device *dev) { - struct device *ne_dev, *next; - - list_for_each_entry_safe(ne_dev, next, &dev->children, node) - nodemgr_remove_ne(container_of(ne_dev, struct node_entry, device)); - + device_for_each_child(dev, NULL, __nodemgr_remove_host_dev); sysfs_remove_link(&dev->kobj, "irm_id"); sysfs_remove_link(&dev->kobj, "busmgr_id"); sysfs_remove_link(&dev->kobj, "host_id"); -- cgit v0.10.2 From d0e2b4a0a9dd3eed71b56c47268bf4e40cff6d0f Mon Sep 17 00:00:00 2001 From: long Date: Tue, 29 Mar 2005 13:36:43 -0800 Subject: [PATCH] use device_for_each_child() to properly access child devices. On Friday, March 25, 2005 8:47 PM Greg KH wrote: >Here's a fix for pci express. For some reason I don't think they are >using the driver model properly here, but I could be wrong... Thanks for making the changes. However, changes in functions: void pcie_port_device_remove(struct pci_dev *dev) and static int remove_iter(struct device *dev, void *data) are not correct. Please use the patch, which is based on kernel 2.6.12-rc1, below for a fix for these. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 5762857..f5c5f10 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -232,19 +232,16 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, /* Initialize generic device interface */ device = &dev->device; memset(device, 0, sizeof(struct device)); - INIT_LIST_HEAD(&device->node); - INIT_LIST_HEAD(&device->children); - INIT_LIST_HEAD(&device->bus_list); device->bus = &pcie_port_bus_type; device->driver = NULL; - device->driver_data = NULL; + device->driver_data = NULL; device->release = release_pcie_device; /* callback to free pcie dev */ - sprintf(&device->bus_id[0], "pcie%02x", + sprintf(&device->bus_id[0], "pcie%02x", get_descriptor_id(port_type, service_type)); device->parent = &parent->dev; } -static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, +static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, int port_type, int service_type, int irq, int irq_mode) { struct pcie_device *device; @@ -270,9 +267,9 @@ int pcie_port_device_probe(struct pci_dev *dev) pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®); type = (reg >> 4) & PORT_TYPE_MASK; if ( type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT || - type == PCIE_SW_DOWNSTREAM_PORT ) + type == PCIE_SW_DOWNSTREAM_PORT ) return 0; - + return -ENODEV; } @@ -283,8 +280,8 @@ int pcie_port_device_register(struct pci_dev *dev) u16 reg16; /* Get port type */ - pci_read_config_word(dev, - pci_find_capability(dev, PCI_CAP_ID_EXP) + + pci_read_config_word(dev, + pci_find_capability(dev, PCI_CAP_ID_EXP) + PCIE_CAPABILITIES_REG, ®16); type = (reg16 >> 4) & PORT_TYPE_MASK; @@ -299,11 +296,11 @@ int pcie_port_device_register(struct pci_dev *dev) if (capabilities & (1 << i)) { child = alloc_pcie_device( dev, /* parent */ - type, /* port type */ + type, /* port type */ i, /* service type */ vectors[i], /* irq */ irq_mode /* interrupt mode */); - if (child) { + if (child) { status = device_register(&child->device); if (status) { kfree(child); @@ -317,84 +314,78 @@ int pcie_port_device_register(struct pci_dev *dev) } #ifdef CONFIG_PM -int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state) +static int suspend_iter(struct device *dev, void *data) { - struct list_head *head, *tmp; - struct device *parent, *child; - struct device_driver *driver; struct pcie_port_service_driver *service_driver; + u32 state = (u32)data; + + if ((dev->bus == &pcie_port_bus_type) && + (dev->driver)) { + service_driver = to_service_driver(dev->driver); + if (service_driver->suspend) + service_driver->suspend(to_pcie_device(dev), state); + } + return 0; +} - parent = &dev->dev; - head = &parent->children; - tmp = head->next; - while (head != tmp) { - child = container_of(tmp, struct device, node); - tmp = tmp->next; - if (child->bus != &pcie_port_bus_type) - continue; - driver = child->driver; - if (!driver) - continue; - service_driver = to_service_driver(driver); - if (service_driver->suspend) - service_driver->suspend(to_pcie_device(child), state); - } - return 0; +int pcie_port_device_suspend(struct pci_dev *dev, u32 state) +{ + device_for_each_child(&dev->dev, (void *)state, suspend_iter); + return 0; } -int pcie_port_device_resume(struct pci_dev *dev) -{ - struct list_head *head, *tmp; - struct device *parent, *child; - struct device_driver *driver; +static int resume_iter(struct device *dev, void *data) +{ struct pcie_port_service_driver *service_driver; - parent = &dev->dev; - head = &parent->children; - tmp = head->next; - while (head != tmp) { - child = container_of(tmp, struct device, node); - tmp = tmp->next; - if (child->bus != &pcie_port_bus_type) - continue; - driver = child->driver; - if (!driver) - continue; - service_driver = to_service_driver(driver); - if (service_driver->resume) - service_driver->resume(to_pcie_device(child)); + if ((dev->bus == &pcie_port_bus_type) && + (dev->driver)) { + service_driver = to_service_driver(dev->driver); + if (service_driver->resume) + service_driver->resume(to_pcie_device(dev)); } - return 0; + return 0; +} +int pcie_port_device_resume(struct pci_dev *dev) +{ + device_for_each_child(&dev->dev, NULL, resume_iter); + return 0; } #endif -void pcie_port_device_remove(struct pci_dev *dev) +static int remove_iter(struct device *dev, void *data) { - struct list_head *head, *tmp; - struct device *parent, *child; - struct device_driver *driver; struct pcie_port_service_driver *service_driver; - int interrupt_mode = PCIE_PORT_INTx_MODE; - parent = &dev->dev; - head = &parent->children; - tmp = head->next; - while (head != tmp) { - child = container_of(tmp, struct device, node); - tmp = tmp->next; - if (child->bus != &pcie_port_bus_type) - continue; - driver = child->driver; - if (driver) { - service_driver = to_service_driver(driver); - if (service_driver->remove) - service_driver->remove(to_pcie_device(child)); + if (dev->bus == &pcie_port_bus_type) { + if (dev->driver) { + service_driver = to_service_driver(dev->driver); + if (service_driver->remove) + service_driver->remove(to_pcie_device(dev)); } - interrupt_mode = (to_pcie_device(child))->interrupt_mode; - put_device(child); - device_unregister(child); + *(unsigned long*)data = (unsigned long)dev; + return 1; } + return 0; +} + +void pcie_port_device_remove(struct pci_dev *dev) +{ + struct device *device; + unsigned long device_addr; + int interrupt_mode = PCIE_PORT_INTx_MODE; + int status; + + do { + status = device_for_each_child(&dev->dev, &device_addr, remove_iter); + if (status) { + device = (struct device*)device_addr; + interrupt_mode = (to_pcie_device(device))->interrupt_mode; + put_device(device); + device_unregister(device); + } + } while (status); /* Switch to INTx by default if MSI enabled */ if (interrupt_mode == PCIE_PORT_MSIX_MODE) pci_disable_msix(dev); @@ -423,7 +414,7 @@ int pcie_port_service_register(struct pcie_port_service_driver *new) new->driver.resume = pcie_port_resume_service; return driver_register(&new->driver); -} +} void pcie_port_service_unregister(struct pcie_port_service_driver *new) { -- cgit v0.10.2 From b86c1df1f98d16c999423a3907eb40a9423f481e Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Thu, 31 Mar 2005 12:53:00 -0800 Subject: [PATCH] Driver core: Fix up the driver and device iterators to be quieter Also stops looping over the lists when a match is found. Signed-off-by: Greg Kroah-Hartman name, dev->bus_id, error); + if (error) { + if ((error == -ENODEV) || (error == -ENXIO)) { + /* Driver matched, but didn't support device + * or device not found. + * Not an error; keep going. + */ + error = 0; + } else { + /* driver matched but the probe failed */ + printk(KERN_WARNING + "%s: probe of %s failed with error %d\n", + drv->name, dev->bus_id, error); + } + return error; } - return 0; + /* stop looking, this device is attached */ + return 1; } /** @@ -137,7 +140,10 @@ static int __driver_attach(struct device * dev, void * data) drv->name, dev->bus_id, error); } else error = 0; + return error; } + /* stop looking, this driver is attached */ + return 1; } return 0; } -- cgit v0.10.2 From 0d3e5a2e39b6ba2974e9e7c2a429018c45de8e76 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 5 Apr 2005 23:46:33 -0700 Subject: [PATCH] Driver Core: fix bk-driver-core kills ppc64 There's no check to see if the device is already bound to a driver, which could do bad things. The first thing to go wrong is that it will try to match a driver with a device already bound to one. In some cases (it appears with USB with drivers/usb/core/usb.c::usb_match_id()), some drivers will match a device based on the class type, so it would be common (especially for HID devices) to match a device that is already bound. The fun comes when ->probe() is called, it fails, then driver_probe_device() does this: dev->driver = NULL; Later on, that pointer could be be dereferenced without checking and cause hell to break loose. This problem could be nasty. It's very hardware dependent, since some devices could have a different set of matching qualifiers than others. Now, I don't quite see exactly where/how you were getting that crash. You're dereferencing bad memory, but I'm not sure which pointer was bad and where it came from, but it could have come from a couple of different places. The patch below will hopefully fix it all up for you. It's against 2.6.12-rc2-mm1, and does the following: - Move logic to driver_probe_device() and comments uncommon returns: 1 - If device is bound 0 - If device not bound, and no error error - If there was an error. - Move locking to caller of that function, since we want to lock a device for the entire time we're trying to bind it to a driver (to prevent against a driver being loaded at the same time). - Update __device_attach() and __driver_attach() to do that locking. - Check if device is already bound in __driver_attach() - Update the converse device_release_driver() so it locks the device around all of the operations. - Mark driver_probe_device() as static and remove export. It's an internal function, it should stay that way, and there are no other callers. If there is ever a need to export it, we can audit it as necessary. Signed-off-by: Andrew Morton diff --git a/drivers/base/dd.c b/drivers/base/dd.c index dd2a8a7..8510918 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -35,6 +35,8 @@ * nor take the bus's rwsem. Please verify those are accounted * for before calling this. (It is ok to call with no other effort * from a driver's probe() method.) + * + * This function must be called with @dev->sem held. */ void device_bind_driver(struct device * dev) { @@ -57,54 +59,56 @@ void device_bind_driver(struct device * dev) * because we don't know the format of the ID structures, nor what * is to be considered a match and what is not. * - * If we find a match, we call @drv->probe(@dev) if it exists, and - * call device_bind_driver() above. + * + * This function returns 1 if a match is found, an error if one + * occurs (that is not -ENODEV or -ENXIO), and 0 otherwise. + * + * This function must be called with @dev->sem held. */ -int driver_probe_device(struct device_driver * drv, struct device * dev) +static int driver_probe_device(struct device_driver * drv, struct device * dev) { - int error = 0; + int ret = 0; if (drv->bus->match && !drv->bus->match(dev, drv)) - return -ENODEV; + goto Done; - down(&dev->sem); + pr_debug("%s: Matched Device %s with Driver %s\n", + drv->bus->name, dev->bus_id, drv->name); dev->driver = drv; if (drv->probe) { - error = drv->probe(dev); - if (error) { + ret = drv->probe(dev); + if (ret) { dev->driver = NULL; - up(&dev->sem); - return error; + goto ProbeFailed; } } - up(&dev->sem); device_bind_driver(dev); - return 0; + ret = 1; + pr_debug("%s: Bound Device %s to Driver %s\n", + drv->bus->name, dev->bus_id, drv->name); + goto Done; + + ProbeFailed: + if (ret == -ENODEV || ret == -ENXIO) { + /* Driver matched, but didn't support device + * or device not found. + * Not an error; keep going. + */ + ret = 0; + } else { + /* driver matched but the probe failed */ + printk(KERN_WARNING + "%s: probe of %s failed with error %d\n", + drv->name, dev->bus_id, ret); + } + Done: + return ret; } static int __device_attach(struct device_driver * drv, void * data) { struct device * dev = data; - int error; - - error = driver_probe_device(drv, dev); - if (error) { - if ((error == -ENODEV) || (error == -ENXIO)) { - /* Driver matched, but didn't support device - * or device not found. - * Not an error; keep going. - */ - error = 0; - } else { - /* driver matched but the probe failed */ - printk(KERN_WARNING - "%s: probe of %s failed with error %d\n", - drv->name, dev->bus_id, error); - } - return error; - } - /* stop looking, this device is attached */ - return 1; + return driver_probe_device(drv, dev); } /** @@ -114,37 +118,43 @@ static int __device_attach(struct device_driver * drv, void * data) * Walk the list of drivers that the bus has and call * driver_probe_device() for each pair. If a compatible * pair is found, break out and return. + * + * Returns 1 if the device was bound to a driver; 0 otherwise. */ int device_attach(struct device * dev) { + int ret = 0; + + down(&dev->sem); if (dev->driver) { device_bind_driver(dev); - return 1; - } - - return bus_for_each_drv(dev->bus, NULL, dev, __device_attach); + ret = 1; + } else + ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); + up(&dev->sem); + return ret; } static int __driver_attach(struct device * dev, void * data) { struct device_driver * drv = data; - int error = 0; - - if (!dev->driver) { - error = driver_probe_device(drv, dev); - if (error) { - if (error != -ENODEV) { - /* driver matched but the probe failed */ - printk(KERN_WARNING - "%s: probe of %s failed with error %d\n", - drv->name, dev->bus_id, error); - } else - error = 0; - return error; - } - /* stop looking, this driver is attached */ - return 1; - } + + /* + * Lock device and try to bind to it. We drop the error + * here and always return 0, because we need to keep trying + * to bind to devices and some drivers will return an error + * simply if it didn't support the device. + * + * driver_probe_device() will spit a warning if there + * is an error. + */ + + down(&dev->sem); + if (!dev->driver) + driver_probe_device(drv, dev); + up(&dev->sem); + + return 0; } @@ -156,9 +166,6 @@ static int __driver_attach(struct device * dev, void * data) * match the driver with each one. If driver_probe_device() * returns 0 and the @dev->driver is set, we've found a * compatible pair. - * - * Note that we ignore the -ENODEV error from driver_probe_device(), - * since it's perfectly valid for a driver not to bind to any devices. */ void driver_attach(struct device_driver * drv) { @@ -176,19 +183,19 @@ void driver_attach(struct device_driver * drv) */ void device_release_driver(struct device * dev) { - struct device_driver * drv = dev->driver; - - if (!drv) - return; - - sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); - sysfs_remove_link(&dev->kobj, "driver"); - klist_del(&dev->knode_driver); + struct device_driver * drv; down(&dev->sem); - if (drv->remove) - drv->remove(dev); - dev->driver = NULL; + if (dev->driver) { + drv = dev->driver; + sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); + sysfs_remove_link(&dev->kobj, "driver"); + klist_del(&dev->knode_driver); + + if (drv->remove) + drv->remove(dev); + dev->driver = NULL; + } up(&dev->sem); } @@ -208,7 +215,6 @@ void driver_detach(struct device_driver * drv) } -EXPORT_SYMBOL_GPL(driver_probe_device); EXPORT_SYMBOL_GPL(device_bind_driver); EXPORT_SYMBOL_GPL(device_release_driver); EXPORT_SYMBOL_GPL(device_attach); diff --git a/include/linux/device.h b/include/linux/device.h index 4324926..91aac34 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -325,7 +325,6 @@ extern int device_for_each_child(struct device *, void *, * Manual binding of a device to driver. See drivers/base/bus.c * for information on use. */ -extern int driver_probe_device(struct device_driver * drv, struct device * dev); extern void device_bind_driver(struct device * dev); extern void device_release_driver(struct device * dev); extern int device_attach(struct device * dev); -- cgit v0.10.2 From 12eac738e5889a10da5b391c02eeb61229c796dc Mon Sep 17 00:00:00 2001 From: Jason Uhlenkott Date: Wed, 30 Mar 2005 13:19:54 -0800 Subject: [PATCH] Fix typo in scdrv_init() Fix a typo in scdrv_init() which was breaking the build for SGI sn2. Signed-off-by: Jason Uhlenkott Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 901d6f1..261a41b 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -437,7 +437,7 @@ scdrv_init(void) continue; } - class__device_create(snsc_class, dev, NULL, + class_device_create(snsc_class, dev, NULL, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, -- cgit v0.10.2 From 273971bade8a6d37c1b162146de1a53965cdc245 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 20 Jun 2005 15:15:28 -0700 Subject: [PATCH] usb: klist_node_attached() fix The original code looks like this: /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() */ if (!list_empty (&dev->bus_list)) device_bind_driver(dev); IOW, it's checking to see if the device is attached to the bus or not and binding the driver if it is. It's checking the device's bus list, which will only appear empty when the device has been initialized, but not added. It depends way too much on the driver model internals, but it seems to be the only way to do the weird crap they want to do with interfaces. When I converted it to use klists, I accidentally inverted the logic, which led to bad things happening. This patch returns the check to its orginal value. From: Patrick Mochel Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman Index: gregkh-2.6/drivers/usb/core/usb.c =================================================================== diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 230839a..6667876 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -293,7 +293,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() */ - if (!klist_node_attached (&dev->knode_bus)) + if (klist_node_attached(&dev->knode_bus)) device_bind_driver(dev); return 0; -- cgit v0.10.2 From 6623415687eaffef49429292ab062bb046ee3311 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Thu, 28 Apr 2005 17:11:52 -0700 Subject: [PATCH] sn: fixes due to driver core changes Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index ab9b5f3..b6bcfe0 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c @@ -518,25 +518,22 @@ static int __init tiocx_init(void) return 0; } -static void __exit tiocx_exit(void) +static int cx_remove_device(struct device * dev, void * data) { - struct device *dev; - struct device *tdev; + struct cx_dev *cx_dev = to_cx_dev(dev); + device_remove_file(dev, &dev_attr_cxdev_control); + cx_device_unregister(cx_dev); + return 0; +} +static void __exit tiocx_exit(void) +{ DBG("tiocx_exit\n"); /* * Unregister devices. */ - list_for_each_entry_safe(dev, tdev, &tiocx_bus_type.devices.list, - bus_list) { - if (dev) { - struct cx_dev *cx_dev = to_cx_dev(dev); - device_remove_file(dev, &dev_attr_cxdev_control); - cx_device_unregister(cx_dev); - } - } - + bus_for_each_dev(&tiocx_bus_type, NULL, NULL, cx_remove_device); bus_unregister(&tiocx_bus_type); } -- cgit v0.10.2 From c95a6b057b108c2b7add35cba1354f9af921349e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 6 May 2005 15:38:33 -0400 Subject: [PATCH] driver core: Fix races in driver_detach() This patch is intended for your "driver" tree. It fixes several subtle races in driver_detach() and device_release_driver() in the driver-model core. The major change is to use klist_remove() rather than klist_del() when taking a device off its driver's list. There's no other way to guarantee that the list pointers will be updated before some other driver binds to the device. For this to work driver_detach() can't use a klist iterator, so the loop over the devices must be written out in full. In addition the patch protects against the possibility that, when a driver and a device are unregistered at the same time, one may be unloaded from memory before the other is finished using it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 8510918..eab2030 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -177,41 +177,66 @@ void driver_attach(struct device_driver * drv) * @dev: device. * * Manually detach device from driver. - * Note that this is called without incrementing the bus - * reference count nor taking the bus's rwsem. Be sure that - * those are accounted for before calling this function. + * + * __device_release_driver() must be called with @dev->sem held. */ -void device_release_driver(struct device * dev) + +static void __device_release_driver(struct device * dev) { struct device_driver * drv; - down(&dev->sem); - if (dev->driver) { - drv = dev->driver; + drv = dev->driver; + if (drv) { + get_driver(drv); sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&dev->kobj, "driver"); - klist_del(&dev->knode_driver); + klist_remove(&dev->knode_driver); if (drv->remove) drv->remove(dev); dev->driver = NULL; + put_driver(drv); } - up(&dev->sem); } -static int __remove_driver(struct device * dev, void * unused) +void device_release_driver(struct device * dev) { - device_release_driver(dev); - return 0; + /* + * If anyone calls device_release_driver() recursively from + * within their ->remove callback for the same device, they + * will deadlock right here. + */ + down(&dev->sem); + __device_release_driver(dev); + up(&dev->sem); } + /** * driver_detach - detach driver from all devices it controls. * @drv: driver. */ void driver_detach(struct device_driver * drv) { - driver_for_each_device(drv, NULL, NULL, __remove_driver); + struct device * dev; + + for (;;) { + spin_lock_irq(&drv->klist_devices.k_lock); + if (list_empty(&drv->klist_devices.k_list)) { + spin_unlock_irq(&drv->klist_devices.k_lock); + break; + } + dev = list_entry(drv->klist_devices.k_list.prev, + struct device, knode_driver.n_node); + get_device(dev); + spin_unlock_irq(&drv->klist_devices.k_lock); + + down(&dev->sem); + if (dev->driver == drv) + __device_release_driver(dev); + up(&dev->sem); + put_device(dev); + } } -- cgit v0.10.2 From f409661877a25d11c2495bcd879807f17c286684 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 6 May 2005 15:41:08 -0400 Subject: [PATCH] usbcore: Don't call device_release_driver recursively This patch fixes usb_driver_release_interface() to make it avoid calling device_release_driver() recursively, i.e., when invoked from within the disconnect routine for the same device. The patch applies to your "driver" tree. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 6667876..a3c4220 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -322,9 +322,15 @@ void usb_driver_release_interface(struct usb_driver *driver, if (!dev->driver || dev->driver != &driver->driver) return; - /* don't disconnect from disconnect(), or before dev_add() */ - if (!klist_node_attached(&dev->knode_driver) && !klist_node_attached(&dev->knode_bus)) + /* don't release from within disconnect() */ + if (iface->condition != USB_INTERFACE_BOUND) + return; + + /* release only after device_add() */ + if (klist_node_attached(&dev->knode_bus)) { + iface->condition = USB_INTERFACE_UNBINDING; device_release_driver(dev); + } dev->driver = NULL; usb_set_intfdata(iface, NULL); -- cgit v0.10.2 From 4b45099b75832434c5113b9aed1499f8a69d13d5 Mon Sep 17 00:00:00 2001 From: Keiichiro Tokunaga Date: Sun, 8 May 2005 21:28:53 +0900 Subject: [PATCH] Driver core: unregister_node() for hotplug use This adds a generic function 'unregister_node()'. It is used to remove objects of a node going away for hotplug. All the devices on the node must be unregistered before calling this function. Signed-off-by: Keiichiro Tokunaga Signed-off-by: Greg Kroah-Hartman diff -puN drivers/base/node.c~numa_hp_base drivers/base/node.c diff --git a/drivers/base/node.c b/drivers/base/node.c index 583d57e..5d4517c 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -136,7 +136,7 @@ static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); * * Initialize and register the node device. */ -int __init register_node(struct node *node, int num, struct node *parent) +int register_node(struct node *node, int num, struct node *parent) { int error; @@ -153,8 +153,24 @@ int __init register_node(struct node *node, int num, struct node *parent) return error; } +/** + * unregister_node - unregister a node device + * @node: node going away + * + * Unregisters a node device @node. All the devices on the node must be + * unregistered before calling this function. + */ +void unregister_node(struct node *node) +{ + sysdev_remove_file(&node->sysdev, &attr_cpumap); + sysdev_remove_file(&node->sysdev, &attr_meminfo); + sysdev_remove_file(&node->sysdev, &attr_numastat); + sysdev_remove_file(&node->sysdev, &attr_distance); + + sysdev_unregister(&node->sysdev); +} -int __init register_node_type(void) +static int __init register_node_type(void) { return sysdev_class_register(&node_class); } diff --git a/include/linux/node.h b/include/linux/node.h index 6e0a697..254dc3d 100644 --- a/include/linux/node.h +++ b/include/linux/node.h @@ -27,6 +27,7 @@ struct node { }; extern int register_node(struct node *, int, struct node *); +extern void unregister_node(struct node *node); #define to_node(sys_device) container_of(sys_device, struct node, sysdev) -- cgit v0.10.2 From 4109aca06cb7b042ea791d0f9d3c9615bc3bf5cd Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 16 May 2005 17:19:55 -0700 Subject: [PATCH] Driver Core: driver model doc update This updates some driver data documentation: - removes references to some fields that haven't been there for a long time now, e.g. pre-kobject or even older; - giving more information about the probe() method; - adding an example of how platform_data is used Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt index 58cc5dc..a05ec50 100644 --- a/Documentation/driver-model/device.txt +++ b/Documentation/driver-model/device.txt @@ -76,6 +76,14 @@ driver_data: Driver-specific data. platform_data: Platform data specific to the device. + Example: for devices on custom boards, as typical of embedded + and SOC based hardware, Linux often uses platform_data to point + to board-specific structures describing devices and how they + are wired. That can include what ports are available, chip + variants, which GPIO pins act in what additional roles, and so + on. This shrinks the "Board Support Packages" (BSPs) and + minimizes board-specific #ifdefs in drivers. + current_state: Current power state of the device. saved_state: Pointer to saved state of the device. This is usable by diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt index 6031a68..fabaca1 100644 --- a/Documentation/driver-model/driver.txt +++ b/Documentation/driver-model/driver.txt @@ -5,21 +5,17 @@ struct device_driver { char * name; struct bus_type * bus; - rwlock_t lock; - atomic_t refcount; - - list_t bus_list; + struct completion unloaded; + struct kobject kobj; list_t devices; - struct driver_dir_entry dir; + struct module *owner; int (*probe) (struct device * dev); int (*remove) (struct device * dev); int (*suspend) (struct device * dev, pm_message_t state, u32 level); int (*resume) (struct device * dev, u32 level); - - void (*release) (struct device_driver * drv); }; @@ -51,7 +47,6 @@ being converted completely to the new model. static struct device_driver eepro100_driver = { .name = "eepro100", .bus = &pci_bus_type, - .devclass = ðernet_devclass, /* when it's implemented */ .probe = eepro100_probe, .remove = eepro100_remove, @@ -85,7 +80,6 @@ static struct pci_driver eepro100_driver = { .driver = { .name = "eepro100", .bus = &pci_bus_type, - .devclass = ðernet_devclass, /* when it's implemented */ .probe = eepro100_probe, .remove = eepro100_remove, .suspend = eepro100_suspend, @@ -166,27 +160,32 @@ Callbacks int (*probe) (struct device * dev); -probe is called to verify the existence of a certain type of -hardware. This is called during the driver binding process, after the -bus has verified that the device ID of a device matches one of the -device IDs supported by the driver. - -This callback only verifies that there actually is supported hardware -present. It may allocate a driver-specific structure, but it should -not do any initialization of the hardware itself. The device-specific -structure may be stored in the device's driver_data field. - - int (*init) (struct device * dev); - -init is called during the binding stage. It is called after probe has -successfully returned and the device has been registered with its -class. It is responsible for initializing the hardware. +The probe() entry is called in task context, with the bus's rwsem locked +and the driver partially bound to the device. Drivers commonly use +container_of() to convert "dev" to a bus-specific type, both in probe() +and other routines. That type often provides device resource data, such +as pci_dev.resource[] or platform_device.resources, which is used in +addition to dev->platform_data to initialize the driver. + +This callback holds the driver-specific logic to bind the driver to a +given device. That includes verifying that the device is present, that +it's a version the driver can handle, that driver data structures can +be allocated and initialized, and that any hardware can be initialized. +Drivers often store a pointer to their state with dev_set_drvdata(). +When the driver has successfully bound itself to that device, then probe() +returns zero and the driver model code will finish its part of binding +the driver to that device. + +A driver's probe() may return a negative errno value to indicate that +the driver did not bind to this device, in which case it should have +released all reasources it allocated. int (*remove) (struct device * dev); -remove is called to dissociate a driver with a device. This may be +remove is called to unbind a driver from a device. This may be called if a device is physically removed from the system, if the -driver module is being unloaded, or during a reboot sequence. +driver module is being unloaded, during a reboot sequence, or +in other cases. It is up to the driver to determine if the device is present or not. It should free any resources allocated specifically for the -- cgit v0.10.2 From acaefc25d21f850e47ecc5098d1e0bc442c526be Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 May 2005 14:40:59 +0200 Subject: [PATCH] libfs: add simple attribute files Based on the discussion about spufs attributes, this is my suggestion for a more generic attribute file support that can be used by both debugfs and spufs. Simple attribute files behave similarly to sequential files from a kernel programmers perspective in that a standard set of file operations is provided and only an open operation needs to be written that registers file specific get() and set() functions. These operations are defined as void foo_set(void *data, u64 val); and u64 foo_get(void *data); where data is the inode->u.generic_ip pointer of the file and the operations just need to make send of that pointer. The infrastructure makes sure this works correctly with concurrent access and partial read calls. A macro named DEFINE_SIMPLE_ATTRIBUTE is provided to further simplify using the attributes. This patch already contains the changes for debugfs to use attributes for its internal file operations. Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 548556f..efc97d9 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -45,44 +45,15 @@ struct file_operations debugfs_file_operations = { .open = default_open, }; -#define simple_type(type, format, temptype, strtolfn) \ -static ssize_t read_file_##type(struct file *file, char __user *user_buf, \ - size_t count, loff_t *ppos) \ -{ \ - char buf[32]; \ - type *val = file->private_data; \ - \ - snprintf(buf, sizeof(buf), format "\n", *val); \ - return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));\ -} \ -static ssize_t write_file_##type(struct file *file, const char __user *user_buf,\ - size_t count, loff_t *ppos) \ -{ \ - char *endp; \ - char buf[32]; \ - int buf_size; \ - type *val = file->private_data; \ - temptype tmp; \ - \ - memset(buf, 0x00, sizeof(buf)); \ - buf_size = min(count, (sizeof(buf)-1)); \ - if (copy_from_user(buf, user_buf, buf_size)) \ - return -EFAULT; \ - \ - tmp = strtolfn(buf, &endp, 0); \ - if ((endp == buf) || ((type)tmp != tmp)) \ - return -EINVAL; \ - *val = tmp; \ - return count; \ -} \ -static struct file_operations fops_##type = { \ - .read = read_file_##type, \ - .write = write_file_##type, \ - .open = default_open, \ -}; -simple_type(u8, "%c", unsigned long, simple_strtoul); -simple_type(u16, "%hi", unsigned long, simple_strtoul); -simple_type(u32, "%i", unsigned long, simple_strtoul); +static void debugfs_u8_set(void *data, u64 val) +{ + *(u8 *)data = val; +} +static u64 debugfs_u8_get(void *data) +{ + return *(u8 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n"); /** * debugfs_create_u8 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. @@ -116,6 +87,16 @@ struct dentry *debugfs_create_u8(const char *name, mode_t mode, } EXPORT_SYMBOL_GPL(debugfs_create_u8); +static void debugfs_u16_set(void *data, u64 val) +{ + *(u16 *)data = val; +} +static u64 debugfs_u16_get(void *data) +{ + return *(u16 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n"); + /** * debugfs_create_u16 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. * @@ -148,6 +129,16 @@ struct dentry *debugfs_create_u16(const char *name, mode_t mode, } EXPORT_SYMBOL_GPL(debugfs_create_u16); +static void debugfs_u32_set(void *data, u64 val) +{ + *(u32 *)data = val; +} +static u64 debugfs_u32_get(void *data) +{ + return *(u32 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n"); + /** * debugfs_create_u32 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. * diff --git a/fs/libfs.c b/fs/libfs.c index f90b295..5025563 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -519,6 +519,102 @@ int simple_transaction_release(struct inode *inode, struct file *file) return 0; } +/* Simple attribute files */ + +struct simple_attr { + u64 (*get)(void *); + void (*set)(void *, u64); + char get_buf[24]; /* enough to store a u64 and "\n\0" */ + char set_buf[24]; + void *data; + const char *fmt; /* format for read operation */ + struct semaphore sem; /* protects access to these buffers */ +}; + +/* simple_attr_open is called by an actual attribute open file operation + * to set the attribute specific access operations. */ +int simple_attr_open(struct inode *inode, struct file *file, + u64 (*get)(void *), void (*set)(void *, u64), + const char *fmt) +{ + struct simple_attr *attr; + + attr = kmalloc(sizeof(*attr), GFP_KERNEL); + if (!attr) + return -ENOMEM; + + attr->get = get; + attr->set = set; + attr->data = inode->u.generic_ip; + attr->fmt = fmt; + init_MUTEX(&attr->sem); + + file->private_data = attr; + + return nonseekable_open(inode, file); +} + +int simple_attr_close(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +/* read from the buffer that is filled with the get function */ +ssize_t simple_attr_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + struct simple_attr *attr; + size_t size; + ssize_t ret; + + attr = file->private_data; + + if (!attr->get) + return -EACCES; + + down(&attr->sem); + if (*ppos) /* continued read */ + size = strlen(attr->get_buf); + else /* first read */ + size = scnprintf(attr->get_buf, sizeof(attr->get_buf), + attr->fmt, + (unsigned long long)attr->get(attr->data)); + + ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); + up(&attr->sem); + return ret; +} + +/* interpret the buffer as a number to call the set function with */ +ssize_t simple_attr_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct simple_attr *attr; + u64 val; + size_t size; + ssize_t ret; + + attr = file->private_data; + + if (!attr->set) + return -EACCES; + + down(&attr->sem); + ret = -EFAULT; + size = min(sizeof(attr->set_buf) - 1, len); + if (copy_from_user(attr->set_buf, buf, size)) + goto out; + + ret = len; /* claim we got the whole input */ + attr->set_buf[size] = '\0'; + val = simple_strtol(attr->set_buf, NULL, 0); + attr->set(attr->data, val); +out: + up(&attr->sem); + return ret; +} + EXPORT_SYMBOL(dcache_dir_close); EXPORT_SYMBOL(dcache_dir_lseek); EXPORT_SYMBOL(dcache_dir_open); @@ -547,3 +643,7 @@ EXPORT_SYMBOL(simple_read_from_buffer); EXPORT_SYMBOL(simple_transaction_get); EXPORT_SYMBOL(simple_transaction_read); EXPORT_SYMBOL(simple_transaction_release); +EXPORT_SYMBOL_GPL(simple_attr_open); +EXPORT_SYMBOL_GPL(simple_attr_close); +EXPORT_SYMBOL_GPL(simple_attr_read); +EXPORT_SYMBOL_GPL(simple_attr_write); diff --git a/include/linux/fs.h b/include/linux/fs.h index 0180102..9b8b696 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1657,6 +1657,52 @@ static inline void simple_transaction_set(struct file *file, size_t n) ar->size = n; } +/* + * simple attribute files + * + * These attributes behave similar to those in sysfs: + * + * Writing to an attribute immediately sets a value, an open file can be + * written to multiple times. + * + * Reading from an attribute creates a buffer from the value that might get + * read with multiple read calls. When the attribute has been read + * completely, no further read calls are possible until the file is opened + * again. + * + * All attributes contain a text representation of a numeric value + * that are accessed with the get() and set() functions. + */ +#define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ +static int __fops ## _open(struct inode *inode, struct file *file) \ +{ \ + __simple_attr_check_format(__fmt, 0ull); \ + return simple_attr_open(inode, file, __get, __set, __fmt); \ +} \ +static struct file_operations __fops = { \ + .owner = THIS_MODULE, \ + .open = __fops ## _open, \ + .release = simple_attr_close, \ + .read = simple_attr_read, \ + .write = simple_attr_write, \ +}; + +static inline void __attribute__((format(printf, 1, 2))) +__simple_attr_check_format(const char *fmt, ...) +{ + /* don't do anything, just let the compiler check the arguments; */ +} + +int simple_attr_open(struct inode *inode, struct file *file, + u64 (*get)(void *), void (*set)(void *, u64), + const char *fmt); +int simple_attr_close(struct inode *inode, struct file *file); +ssize_t simple_attr_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos); +ssize_t simple_attr_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos); + + #ifdef CONFIG_SECURITY static inline char *alloc_secdata(void) { -- cgit v0.10.2 From ca2b94ba12f3c36fd3d6ed9d38b3798d4dad0d8b Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 18 May 2005 10:42:23 +0200 Subject: [PATCH] driver core: fix error handling in bus_add_device The error handling in bus_add_device() and device_attach() is simply non-existing. This patch propagates any error from device_attach to the upper layers to allow for a proper recovery. From: Hannes Reinecke Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 4eb1952..43722af 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -270,11 +270,14 @@ int bus_add_device(struct device * dev) if (bus) { pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); - device_attach(dev); + error = device_attach(dev); klist_add_tail(&bus->klist_devices, &dev->knode_bus); - device_add_attrs(bus, dev); - sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); - sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus"); + if (error >= 0) + error = device_add_attrs(bus, dev); + if (!error) { + sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); + sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus"); + } } return error; } @@ -394,7 +397,7 @@ static int bus_rescan_devices_helper(struct device *dev, void *data) { int *count = data; - if (!dev->driver && device_attach(dev)) + if (!dev->driver && (device_attach(dev) > 0)) (*count)++; return 0; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index eab2030..6db3a78 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -119,7 +119,8 @@ static int __device_attach(struct device_driver * drv, void * data) * driver_probe_device() for each pair. If a compatible * pair is found, break out and return. * - * Returns 1 if the device was bound to a driver; 0 otherwise. + * Returns 1 if the device was bound to a driver; + * 0 if no matching device was found; error code otherwise. */ int device_attach(struct device * dev) { -- cgit v0.10.2 From 54b6f35c99974e99e64c05c2895718355123c55f Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:39:34 -0400 Subject: [PATCH] Driver core: change device_attribute callbacks This patch adds the device_attribute paramerter to the device_attribute store and show sysfs callback functions, and passes a reference to the attribute when the callbacks are called. Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/core.c b/drivers/base/core.c index 1d8c779..86d7975 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -39,7 +39,7 @@ dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) ssize_t ret = -EIO; if (dev_attr->show) - ret = dev_attr->show(dev, buf); + ret = dev_attr->show(dev, dev_attr, buf); return ret; } @@ -52,7 +52,7 @@ dev_attr_store(struct kobject * kobj, struct attribute * attr, ssize_t ret = -EIO; if (dev_attr->store) - ret = dev_attr->store(dev, buf, count); + ret = dev_attr->store(dev, dev_attr, buf, count); return ret; } diff --git a/include/linux/device.h b/include/linux/device.h index 91aac34..7b781a7 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -335,8 +335,10 @@ extern void driver_attach(struct device_driver * drv); struct device_attribute { struct attribute attr; - ssize_t (*show)(struct device * dev, char * buf); - ssize_t (*store)(struct device * dev, const char * buf, size_t count); + ssize_t (*show)(struct device *dev, struct device_attribute *attr, + char *buf); + ssize_t (*store)(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); }; #define DEVICE_ATTR(_name,_mode,_show,_store) \ -- cgit v0.10.2 From 3eb8c7836eb074b61d63597be3e4f085814ac4c0 Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:40:28 -0400 Subject: [PATCH] Driver core: Documentation: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt index 60f6c2c..dc27659 100644 --- a/Documentation/filesystems/sysfs.txt +++ b/Documentation/filesystems/sysfs.txt @@ -214,7 +214,7 @@ Other notes: A very simple (and naive) implementation of a device attribute is: -static ssize_t show_name(struct device * dev, char * buf) +static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf,"%s\n",dev->name); } -- cgit v0.10.2 From ff381d2223a30ee70752791fd9c3588d8f1cab77 Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:40:51 -0400 Subject: [PATCH] Driver Core: arch: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/common/amba.c b/arch/arm/common/amba.c index a0507f8..c6beb75 100644 --- a/arch/arm/common/amba.c +++ b/arch/arm/common/amba.c @@ -169,7 +169,7 @@ static void amba_device_release(struct device *dev) } #define amba_attr(name,fmt,arg...) \ -static ssize_t show_##name(struct device *_dev, char *buf) \ +static ssize_t show_##name(struct device *_dev, struct device_attribute *attr, char *buf) \ { \ struct amba_device *dev = to_amba_device(_dev); \ return sprintf(buf, fmt, arg); \ diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 3dc15b1..6540db6 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -866,19 +866,19 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot) return ec; } -static ssize_t ecard_show_irq(struct device *dev, char *buf) +static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->irq); } -static ssize_t ecard_show_dma(struct device *dev, char *buf) +static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->dma); } -static ssize_t ecard_show_resources(struct device *dev, char *buf) +static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); char *str = buf; @@ -893,19 +893,19 @@ static ssize_t ecard_show_resources(struct device *dev, char *buf) return str - buf; } -static ssize_t ecard_show_vendor(struct device *dev, char *buf) +static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->cid.manufacturer); } -static ssize_t ecard_show_device(struct device *dev, char *buf) +static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->cid.product); } -static ssize_t ecard_show_type(struct device *dev, char *buf) +static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC"); diff --git a/arch/arm26/kernel/ecard.c b/arch/arm26/kernel/ecard.c index 824c6b5..f2278aa 100644 --- a/arch/arm26/kernel/ecard.c +++ b/arch/arm26/kernel/ecard.c @@ -562,31 +562,31 @@ static void __init ecard_init_resources(struct expansion_card *ec) } } -static ssize_t ecard_show_irq(struct device *dev, char *buf) +static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->irq); } -static ssize_t ecard_show_vendor(struct device *dev, char *buf) +static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->cid.manufacturer); } -static ssize_t ecard_show_device(struct device *dev, char *buf) +static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->cid.product); } -static ssize_t ecard_show_dma(struct device *dev, char *buf) +static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->dma); } -static ssize_t ecard_show_resources(struct device *dev, char *buf) +static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); char *str = buf; diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index b6bcfe0..a087b27 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c @@ -432,7 +432,7 @@ static int tiocx_reload(struct cx_dev *cx_dev) return cx_device_reload(cx_dev); } -static ssize_t show_cxdev_control(struct device *dev, char *buf) +static ssize_t show_cxdev_control(struct device *dev, struct device_attribute *attr, char *buf) { struct cx_dev *cx_dev = to_cx_dev(dev); @@ -442,7 +442,7 @@ static ssize_t show_cxdev_control(struct device *dev, char *buf) tiocx_btchar_get(cx_dev->cx_id.nasid)); } -static ssize_t store_cxdev_control(struct device *dev, const char *buf, +static ssize_t store_cxdev_control(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int n; diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index ebf1866..d34bbe7 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -466,7 +466,7 @@ static int parisc_generic_match(struct device *dev, struct device_driver *drv) } #define pa_dev_attr(name, field, format_string) \ -static ssize_t name##_show(struct device *dev, char *buf) \ +static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct parisc_device *padev = to_parisc_device(dev); \ return sprintf(buf, format_string, padev->field); \ diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 47a1530..6d7b92d 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1003,7 +1003,7 @@ pci_create_OF_bus_map(void) } } -static ssize_t pci_show_devspec(struct device *dev, char *buf) +static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev; struct device_node *np; diff --git a/arch/ppc/syslib/ocp.c b/arch/ppc/syslib/ocp.c index a5156c5..e5fd2ae 100644 --- a/arch/ppc/syslib/ocp.c +++ b/arch/ppc/syslib/ocp.c @@ -68,7 +68,7 @@ static int ocp_inited; /* Sysfs support */ #define OCP_DEF_ATTR(field, format_string) \ static ssize_t \ -show_##field(struct device *dev, char *buf) \ +show_##field(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct ocp_device *odev = to_ocp_dev(dev); \ \ diff --git a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c index 46269ed..49c0e34 100644 --- a/arch/ppc/syslib/of_device.c +++ b/arch/ppc/syslib/of_device.c @@ -161,7 +161,7 @@ void of_unregister_driver(struct of_platform_driver *drv) } -static ssize_t dev_show_devspec(struct device *dev, char *buf) +static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) { struct of_device *ofdev; diff --git a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c index f4c825a..66bd5ab7 100644 --- a/arch/ppc64/kernel/of_device.c +++ b/arch/ppc64/kernel/of_device.c @@ -161,7 +161,7 @@ void of_unregister_driver(struct of_platform_driver *drv) } -static ssize_t dev_show_devspec(struct device *dev, char *buf) +static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) { struct of_device *ofdev; diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index d786d4b..2bf0513 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -507,7 +507,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, } #ifdef CONFIG_PPC_MULTIPLATFORM -static ssize_t pci_show_devspec(struct device *dev, char *buf) +static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev; struct device_node *np; diff --git a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c index cdd830c..79f2dc7 100644 --- a/arch/ppc64/kernel/vio.c +++ b/arch/ppc64/kernel/vio.c @@ -300,7 +300,7 @@ static void __devinit vio_dev_release(struct device *dev) } #ifdef CONFIG_PPC_PSERIES -static ssize_t viodev_show_devspec(struct device *dev, char *buf) +static ssize_t viodev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) { struct device_node *of_node = dev->platform_data; @@ -309,7 +309,7 @@ static ssize_t viodev_show_devspec(struct device *dev, char *buf) DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL); #endif -static ssize_t viodev_show_name(struct device *dev, char *buf) +static ssize_t viodev_show_name(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", to_vio_dev(dev)->name); } -- cgit v0.10.2 From 74880c063b06efd103c924abfe19d9d8fa4864c4 Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:41:12 -0400 Subject: [PATCH] Driver Core: drivers/base - drivers/i2c/chips/adm1026.c: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index f48833d..c4aebf2 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c @@ -41,7 +41,7 @@ struct dma_page { /* cacheable header for 'allocation' bytes */ static DECLARE_MUTEX (pools_lock); static ssize_t -show_pools (struct device *dev, char *buf) +show_pools (struct device *dev, struct device_attribute *attr, char *buf) { unsigned temp; unsigned size; diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 6ac9634..f82b3df 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -24,12 +24,12 @@ * low-power state. */ -static ssize_t state_show(struct device * dev, char * buf) +static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf) { return sprintf(buf, "%u\n", dev->power.power_state); } -static ssize_t state_store(struct device * dev, const char * buf, size_t n) +static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n) { u32 state; char * rest; diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 19c5e59..685f061 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -430,7 +430,7 @@ static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd, } } -static ssize_t ub_diag_show(struct device *dev, char *page) +static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr, char *page) { struct usb_interface *intf; struct ub_dev *sc; diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index abfbdcf..3236d24 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -1466,7 +1466,7 @@ static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) } /* The sysfs interface for the driver and devices */ -static ssize_t hvcs_partner_vtys_show(struct device *dev, char *buf) +static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); @@ -1480,7 +1480,7 @@ static ssize_t hvcs_partner_vtys_show(struct device *dev, char *buf) } static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL); -static ssize_t hvcs_partner_clcs_show(struct device *dev, char *buf) +static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); @@ -1494,7 +1494,7 @@ static ssize_t hvcs_partner_clcs_show(struct device *dev, char *buf) } static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL); -static ssize_t hvcs_current_vty_store(struct device *dev, const char * buf, +static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { /* @@ -1505,7 +1505,7 @@ static ssize_t hvcs_current_vty_store(struct device *dev, const char * buf, return -EPERM; } -static ssize_t hvcs_current_vty_show(struct device *dev, char *buf) +static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); @@ -1521,7 +1521,7 @@ static ssize_t hvcs_current_vty_show(struct device *dev, char *buf) static DEVICE_ATTR(current_vty, S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store); -static ssize_t hvcs_vterm_state_store(struct device *dev, const char *buf, +static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vio_dev *viod = to_vio_dev(dev); @@ -1559,7 +1559,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, const char *buf, return count; } -static ssize_t hvcs_vterm_state_show(struct device *dev, char *buf) +static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); @@ -1574,7 +1574,7 @@ static ssize_t hvcs_vterm_state_show(struct device *dev, char *buf) static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, hvcs_vterm_state_show, hvcs_vterm_state_store); -static ssize_t hvcs_index_show(struct device *dev, char *buf) +static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index ac9cfa9..115dbb3 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -699,7 +699,7 @@ static inline int mbcs_hw_init(struct mbcs_soft *soft) return 0; } -static ssize_t show_algo(struct device *dev, char *buf) +static ssize_t show_algo(struct device *dev, struct device_attribute *attr, char *buf) { struct cx_dev *cx_dev = to_cx_dev(dev); struct mbcs_soft *soft = cx_dev->soft; @@ -715,7 +715,7 @@ static ssize_t show_algo(struct device *dev, char *buf) (debug0 >> 32), (debug0 & 0xffffffff)); } -static ssize_t store_algo(struct device *dev, const char *buf, size_t count) +static ssize_t store_algo(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int n; struct cx_dev *cx_dev = to_cx_dev(dev); diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index d37625d..d568991 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c @@ -472,7 +472,7 @@ struct device mwave_device; /* Prevent code redundancy, create a macro for mwave_show_* functions. */ #define mwave_show_function(attr_name, format_string, field) \ -static ssize_t mwave_show_##attr_name(struct device *dev, char *buf) \ +static ssize_t mwave_show_##attr_name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ DSP_3780I_CONFIG_SETTINGS *pSettings = \ &mwave_s_mdd.rBDData.rDspSettings; \ diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 8723533..8ce508b 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -212,7 +212,7 @@ static u8 pcrread[] = { 0, 0, 0, 0 /* PCR index */ }; -static ssize_t show_pcrs(struct device *dev, char *buf) +static ssize_t show_pcrs(struct device *dev, struct device_attribute *attr, char *buf) { u8 data[READ_PCR_RESULT_SIZE]; ssize_t len; @@ -255,7 +255,7 @@ static u8 readpubek[] = { 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ }; -static ssize_t show_pubek(struct device *dev, char *buf) +static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, char *buf) { u8 data[READ_PUBEK_RESULT_SIZE]; ssize_t len; @@ -330,7 +330,7 @@ static u8 cap_manufacturer[] = { 0, 0, 1, 3 }; -static ssize_t show_caps(struct device *dev, char *buf) +static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char *buf) { u8 data[READ_PUBEK_RESULT_SIZE]; ssize_t len; diff --git a/drivers/dio/dio-sysfs.c b/drivers/dio/dio-sysfs.c index d30591f..f464630 100644 --- a/drivers/dio/dio-sysfs.c +++ b/drivers/dio/dio-sysfs.c @@ -17,7 +17,7 @@ /* show configuration fields */ -static ssize_t dio_show_id(struct device *dev, char *buf) +static ssize_t dio_show_id(struct device *dev, struct device_attribute *attr, char *buf) { struct dio_dev *d; @@ -26,7 +26,7 @@ static ssize_t dio_show_id(struct device *dev, char *buf) } static DEVICE_ATTR(id, S_IRUGO, dio_show_id, NULL); -static ssize_t dio_show_ipl(struct device *dev, char *buf) +static ssize_t dio_show_ipl(struct device *dev, struct device_attribute *attr, char *buf) { struct dio_dev *d; @@ -35,7 +35,7 @@ static ssize_t dio_show_ipl(struct device *dev, char *buf) } static DEVICE_ATTR(ipl, S_IRUGO, dio_show_ipl, NULL); -static ssize_t dio_show_secid(struct device *dev, char *buf) +static ssize_t dio_show_secid(struct device *dev, struct device_attribute *attr, char *buf) { struct dio_dev *d; @@ -44,7 +44,7 @@ static ssize_t dio_show_secid(struct device *dev, char *buf) } static DEVICE_ATTR(secid, S_IRUGO, dio_show_secid, NULL); -static ssize_t dio_show_name(struct device *dev, char *buf) +static ssize_t dio_show_name(struct device *dev, struct device_attribute *attr, char *buf) { struct dio_dev *d; @@ -53,7 +53,7 @@ static ssize_t dio_show_name(struct device *dev, char *buf) } static DEVICE_ATTR(name, S_IRUGO, dio_show_name, NULL); -static ssize_t dio_show_resource(struct device *dev, char *buf) +static ssize_t dio_show_resource(struct device *dev, struct device_attribute *attr, char *buf) { struct dio_dev *d = to_dio_dev(dev); diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index 6381ba5..1937743 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -149,7 +149,7 @@ void eisa_driver_unregister (struct eisa_driver *edrv) driver_unregister (&edrv->driver); } -static ssize_t eisa_show_sig (struct device *dev, char *buf) +static ssize_t eisa_show_sig (struct device *dev, struct device_attribute *attr, char *buf) { struct eisa_device *edev = to_eisa_device (dev); return sprintf (buf,"%s\n", edev->id.sig); @@ -157,7 +157,7 @@ static ssize_t eisa_show_sig (struct device *dev, char *buf) static DEVICE_ATTR(signature, S_IRUGO, eisa_show_sig, NULL); -static ssize_t eisa_show_state (struct device *dev, char *buf) +static ssize_t eisa_show_state (struct device *dev, struct device_attribute *attr, char *buf) { struct eisa_device *edev = to_eisa_device (dev); return sprintf (buf,"%d\n", edev->state & EISA_CONFIG_ENABLED); diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index 9c59a37..9058c39 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -137,7 +137,7 @@ static struct i2c_driver adm1021_driver = { }; #define show(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct adm1021_data *data = adm1021_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ @@ -150,7 +150,7 @@ show(remote_temp_hyst); show(remote_temp_input); #define show2(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct adm1021_data *data = adm1021_update_device(dev); \ return sprintf(buf, "%d\n", data->value); \ @@ -159,7 +159,7 @@ show2(alarms); show2(die_code); #define set(value, reg) \ -static ssize_t set_##value(struct device *dev, const char *buf, size_t count) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct adm1021_data *data = i2c_get_clientdata(client); \ diff --git a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c index e0771a3..111f0c8 100644 --- a/drivers/i2c/chips/adm1025.c +++ b/drivers/i2c/chips/adm1025.c @@ -153,19 +153,19 @@ struct adm1025_data { */ #define show_in(offset) \ -static ssize_t show_in##offset(struct device *dev, char *buf) \ +static ssize_t show_in##offset(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct adm1025_data *data = adm1025_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ in_scale[offset])); \ } \ -static ssize_t show_in##offset##_min(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct adm1025_data *data = adm1025_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ in_scale[offset])); \ } \ -static ssize_t show_in##offset##_max(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct adm1025_data *data = adm1025_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ @@ -180,17 +180,17 @@ show_in(4); show_in(5); #define show_temp(offset) \ -static ssize_t show_temp##offset(struct device *dev, char *buf) \ +static ssize_t show_temp##offset(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct adm1025_data *data = adm1025_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ } \ -static ssize_t show_temp##offset##_min(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct adm1025_data *data = adm1025_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ } \ -static ssize_t show_temp##offset##_max(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct adm1025_data *data = adm1025_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ @@ -200,7 +200,7 @@ show_temp(1); show_temp(2); #define set_in(offset) \ -static ssize_t set_in##offset##_min(struct device *dev, const char *buf, \ +static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -214,7 +214,7 @@ static ssize_t set_in##offset##_min(struct device *dev, const char *buf, \ up(&data->update_lock); \ return count; \ } \ -static ssize_t set_in##offset##_max(struct device *dev, const char *buf, \ +static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -240,7 +240,7 @@ set_in(4); set_in(5); #define set_temp(offset) \ -static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \ +static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -254,7 +254,7 @@ static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \ up(&data->update_lock); \ return count; \ } \ -static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \ +static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -275,26 +275,26 @@ static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ set_temp(1); set_temp(2); -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static ssize_t show_vid(struct device *dev, char *buf) +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL); -static ssize_t show_vrm(struct device *dev, char *buf) +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, const char *buf, size_t count) +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1025_data *data = i2c_get_clientdata(client); diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c index 39e2f4a..c127bd9 100644 --- a/drivers/i2c/chips/adm1026.c +++ b/drivers/i2c/chips/adm1026.c @@ -754,24 +754,24 @@ static ssize_t set_in_max(struct device *dev, const char *buf, } #define in_reg(offset) \ -static ssize_t show_in##offset (struct device *dev, char *buf) \ +static ssize_t show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in(dev, buf, offset); \ } \ -static ssize_t show_in##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_min(dev, buf, offset); \ } \ -static ssize_t set_in##offset##_min (struct device *dev, \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_min(dev, buf, count, offset); \ } \ -static ssize_t show_in##offset##_max (struct device *dev, char *buf) \ +static ssize_t show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_max(dev, buf, offset); \ } \ -static ssize_t set_in##offset##_max (struct device *dev, \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_max(dev, buf, count, offset); \ @@ -800,19 +800,19 @@ in_reg(13); in_reg(14); in_reg(15); -static ssize_t show_in16(struct device *dev, char *buf) +static ssize_t show_in16(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in[16]) - NEG12_OFFSET); } -static ssize_t show_in16_min(struct device *dev, char *buf) +static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_min[16]) - NEG12_OFFSET); } -static ssize_t set_in16_min(struct device *dev, const char *buf, size_t count) +static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); @@ -824,13 +824,13 @@ static ssize_t set_in16_min(struct device *dev, const char *buf, size_t count) up(&data->update_lock); return count; } -static ssize_t show_in16_max(struct device *dev, char *buf) +static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_max[16]) - NEG12_OFFSET); } -static ssize_t set_in16_max(struct device *dev, const char *buf, size_t count) +static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); @@ -880,15 +880,15 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, } #define fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_min(dev, buf, offset - 1); \ } \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_min(dev, buf, count, offset - 1); \ @@ -967,11 +967,11 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, } #define fan_offset_div(offset) \ -static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_div(dev, buf, offset - 1); \ } \ -static ssize_t set_fan_##offset##_div (struct device *dev, \ +static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_div(dev, buf, count, offset - 1); \ @@ -1033,24 +1033,24 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, return count; } #define temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp(dev, buf, offset - 1); \ } \ -static ssize_t show_temp_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_min(dev, buf, offset - 1); \ } \ -static ssize_t show_temp_##offset##_max (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_max(dev, buf, offset - 1); \ } \ -static ssize_t set_temp_##offset##_min (struct device *dev, \ +static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_min(dev, buf, count, offset - 1); \ } \ -static ssize_t set_temp_##offset##_max (struct device *dev, \ +static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_max(dev, buf, count, offset - 1); \ @@ -1087,11 +1087,11 @@ static ssize_t set_temp_offset(struct device *dev, const char *buf, } #define temp_offset_reg(offset) \ -static ssize_t show_temp_##offset##_offset (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset##_offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_offset(dev, buf, offset - 1); \ } \ -static ssize_t set_temp_##offset##_offset (struct device *dev, \ +static ssize_t set_temp_##offset##_offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_offset(dev, buf, count, offset - 1); \ @@ -1139,22 +1139,22 @@ static ssize_t set_temp_auto_point1_temp(struct device *dev, const char *buf, } #define temp_auto_point(offset) \ -static ssize_t show_temp##offset##_auto_point1_temp (struct device *dev, \ +static ssize_t show_temp##offset##_auto_point1_temp (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_temp_auto_point1_temp(dev, buf, offset - 1); \ } \ -static ssize_t set_temp##offset##_auto_point1_temp (struct device *dev, \ +static ssize_t set_temp##offset##_auto_point1_temp (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_auto_point1_temp(dev, buf, count, offset - 1); \ } \ static ssize_t show_temp##offset##_auto_point1_temp_hyst (struct device \ - *dev, char *buf) \ + *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_auto_point1_temp_hyst(dev, buf, offset - 1); \ } \ -static ssize_t show_temp##offset##_auto_point2_temp (struct device *dev, \ +static ssize_t show_temp##offset##_auto_point2_temp (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_temp_auto_point2_temp(dev, buf, offset - 1); \ @@ -1171,12 +1171,12 @@ temp_auto_point(1); temp_auto_point(2); temp_auto_point(3); -static ssize_t show_temp_crit_enable(struct device *dev, char *buf) +static ssize_t show_temp_crit_enable(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", (data->config1 & CFG1_THERM_HOT) >> 4); } -static ssize_t set_temp_crit_enable(struct device *dev, const char *buf, +static ssize_t set_temp_crit_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -1224,11 +1224,11 @@ static ssize_t set_temp_crit(struct device *dev, const char *buf, } #define temp_crit_reg(offset) \ -static ssize_t show_temp_##offset##_crit (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_crit(dev, buf, offset - 1); \ } \ -static ssize_t set_temp_##offset##_crit (struct device *dev, \ +static ssize_t set_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_crit(dev, buf, count, offset - 1); \ @@ -1240,12 +1240,12 @@ temp_crit_reg(1); temp_crit_reg(2); temp_crit_reg(3); -static ssize_t show_analog_out_reg(struct device *dev, char *buf) +static ssize_t show_analog_out_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", DAC_FROM_REG(data->analog_out)); } -static ssize_t set_analog_out_reg(struct device *dev, const char *buf, +static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -1262,7 +1262,7 @@ static ssize_t set_analog_out_reg(struct device *dev, const char *buf, static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg, set_analog_out_reg); -static ssize_t show_vid_reg(struct device *dev, char *buf) +static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); @@ -1270,12 +1270,12 @@ static ssize_t show_vid_reg(struct device *dev, char *buf) static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL); -static ssize_t show_vrm_reg(struct device *dev, char *buf) +static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", data->vrm); } -static ssize_t store_vrm_reg(struct device *dev, const char *buf, +static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -1287,7 +1287,7 @@ static ssize_t store_vrm_reg(struct device *dev, const char *buf, static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -static ssize_t show_alarms_reg(struct device *dev, char *buf) +static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%ld\n", (long) (data->alarms)); @@ -1295,12 +1295,12 @@ static ssize_t show_alarms_reg(struct device *dev, char *buf) static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); -static ssize_t show_alarm_mask(struct device *dev, char *buf) +static ssize_t show_alarm_mask(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%ld\n", data->alarm_mask); } -static ssize_t set_alarm_mask(struct device *dev, const char *buf, +static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -1331,12 +1331,12 @@ static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask, set_alarm_mask); -static ssize_t show_gpio(struct device *dev, char *buf) +static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%ld\n", data->gpio); } -static ssize_t set_gpio(struct device *dev, const char *buf, +static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -1359,12 +1359,12 @@ static ssize_t set_gpio(struct device *dev, const char *buf, static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio); -static ssize_t show_gpio_mask(struct device *dev, char *buf) +static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%ld\n", data->gpio_mask); } -static ssize_t set_gpio_mask(struct device *dev, const char *buf, +static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -1386,12 +1386,12 @@ static ssize_t set_gpio_mask(struct device *dev, const char *buf, static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask); -static ssize_t show_pwm_reg(struct device *dev, char *buf) +static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm1.pwm)); } -static ssize_t set_pwm_reg(struct device *dev, const char *buf, +static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -1407,12 +1407,12 @@ static ssize_t set_pwm_reg(struct device *dev, const char *buf, } return count; } -static ssize_t show_auto_pwm_min(struct device *dev, char *buf) +static ssize_t show_auto_pwm_min(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", data->pwm1.auto_pwm_min); } -static ssize_t set_auto_pwm_min(struct device *dev, const char *buf, +static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -1429,16 +1429,16 @@ static ssize_t set_auto_pwm_min(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t show_auto_pwm_max(struct device *dev, char *buf) +static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf,"%d\n", ADM1026_PWM_MAX); } -static ssize_t show_pwm_enable(struct device *dev, char *buf) +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", data->pwm1.enable); } -static ssize_t set_pwm_enable(struct device *dev, const char *buf, +static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); -- cgit v0.10.2 From 30f74292e50d6c4ae438dbee5cb45d77bf774351 Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:41:35 -0400 Subject: [PATCH] Driver Core: drivers/i2c/chips/adm1031.c - lm75.c: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/adm1031.c b/drivers/i2c/chips/adm1031.c index d4385a2..2163dba 100644 --- a/drivers/i2c/chips/adm1031.c +++ b/drivers/i2c/chips/adm1031.c @@ -292,11 +292,11 @@ set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr) } #define fan_auto_channel_offset(offset) \ -static ssize_t show_fan_auto_channel_##offset (struct device *dev, char *buf) \ +static ssize_t show_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_auto_channel(dev, buf, offset - 1); \ } \ -static ssize_t set_fan_auto_channel_##offset (struct device *dev, \ +static ssize_t set_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_auto_channel(dev, buf, count, offset - 1); \ @@ -357,24 +357,24 @@ set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr) } #define auto_temp_reg(offset) \ -static ssize_t show_auto_temp_##offset##_off (struct device *dev, char *buf) \ +static ssize_t show_auto_temp_##offset##_off (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_auto_temp_off(dev, buf, offset - 1); \ } \ -static ssize_t show_auto_temp_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_auto_temp_min(dev, buf, offset - 1); \ } \ -static ssize_t show_auto_temp_##offset##_max (struct device *dev, char *buf) \ +static ssize_t show_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_auto_temp_max(dev, buf, offset - 1); \ } \ -static ssize_t set_auto_temp_##offset##_min (struct device *dev, \ +static ssize_t set_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_auto_temp_min(dev, buf, count, offset - 1); \ } \ -static ssize_t set_auto_temp_##offset##_max (struct device *dev, \ +static ssize_t set_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_auto_temp_max(dev, buf, count, offset - 1); \ @@ -421,11 +421,11 @@ set_pwm(struct device *dev, const char *buf, size_t count, int nr) } #define pwm_reg(offset) \ -static ssize_t show_pwm_##offset (struct device *dev, char *buf) \ +static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_pwm(dev, buf, offset - 1); \ } \ -static ssize_t set_pwm_##offset (struct device *dev, \ +static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_pwm(dev, buf, count, offset - 1); \ @@ -557,24 +557,24 @@ set_fan_div(struct device *dev, const char *buf, size_t count, int nr) } #define fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_min(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_div(dev, buf, offset - 1); \ } \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_min(dev, buf, count, offset - 1); \ } \ -static ssize_t set_fan_##offset##_div (struct device *dev, \ +static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_div(dev, buf, count, offset - 1); \ @@ -667,33 +667,33 @@ set_temp_crit(struct device *dev, const char *buf, size_t count, int nr) } #define temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp(dev, buf, offset - 1); \ } \ -static ssize_t show_temp_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_min(dev, buf, offset - 1); \ } \ -static ssize_t show_temp_##offset##_max (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_max(dev, buf, offset - 1); \ } \ -static ssize_t show_temp_##offset##_crit (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_crit(dev, buf, offset - 1); \ } \ -static ssize_t set_temp_##offset##_min (struct device *dev, \ +static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_min(dev, buf, count, offset - 1); \ } \ -static ssize_t set_temp_##offset##_max (struct device *dev, \ +static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_max(dev, buf, count, offset - 1); \ } \ -static ssize_t set_temp_##offset##_crit (struct device *dev, \ +static ssize_t set_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_crit(dev, buf, count, offset - 1); \ @@ -712,7 +712,7 @@ temp_reg(2); temp_reg(3); /* Alarms */ -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", data->alarm); diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index 7f89900..4a47b44 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -260,28 +260,28 @@ set_in_reg(MAX, max) #define sysfs_in(offset) \ static ssize_t \ - show_in##offset (struct device *dev, char *buf) \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in(dev, buf, offset); \ } \ static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ show_in##offset, NULL); \ static ssize_t \ - show_in##offset##_min (struct device *dev, char *buf) \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_min(dev, buf, offset); \ } \ static ssize_t \ - show_in##offset##_max (struct device *dev, char *buf) \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_max(dev, buf, offset); \ } \ -static ssize_t set_in##offset##_min (struct device *dev, \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_min(dev, buf, count, offset); \ } \ -static ssize_t set_in##offset##_max (struct device *dev, \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_max(dev, buf, count, offset); \ @@ -389,24 +389,24 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, } #define sysfs_fan(offset) \ -static ssize_t show_fan##offset(struct device *dev, char *buf) \ +static ssize_t show_fan##offset(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, offset - 1); \ } \ -static ssize_t show_fan##offset##_min(struct device *dev, char *buf) \ +static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_min(dev, buf, offset - 1); \ } \ -static ssize_t show_fan##offset##_div(struct device *dev, char *buf) \ +static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_div(dev, buf, offset - 1); \ } \ -static ssize_t set_fan##offset##_min(struct device *dev, const char *buf, \ +static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ return set_fan_min(dev, buf, count, offset - 1); \ } \ -static ssize_t set_fan##offset##_div(struct device *dev, const char *buf, \ +static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ return set_fan_div(dev, buf, count, offset - 1); \ @@ -482,27 +482,27 @@ set_temp_reg(MAX, temp_max); set_temp_reg(HYST, temp_hyst); #define sysfs_temp(num) \ -static ssize_t show_temp##num(struct device *dev, char *buf) \ +static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp(dev, buf, num-1); \ } \ static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL); \ -static ssize_t show_temp_max##num(struct device *dev, char *buf) \ +static ssize_t show_temp_max##num(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_max(dev, buf, num-1); \ } \ -static ssize_t set_temp_max##num(struct device *dev, const char *buf, \ +static ssize_t set_temp_max##num(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ return set_temp_max(dev, buf, count, num-1); \ } \ static DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \ show_temp_max##num, set_temp_max##num); \ -static ssize_t show_temp_hyst##num(struct device *dev, char *buf) \ +static ssize_t show_temp_hyst##num(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_hyst(dev, buf, num-1); \ } \ -static ssize_t set_temp_hyst##num(struct device *dev, const char *buf, \ +static ssize_t set_temp_hyst##num(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ return set_temp_hyst(dev, buf, count, num-1); \ @@ -522,7 +522,7 @@ sysfs_temp(4); device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \ } while (0) -static ssize_t show_vid(struct device *dev, char *buf) +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); @@ -533,13 +533,13 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); device_create_file(&client->dev, &dev_attr_cpu0_vid) /* VRM */ -static ssize_t show_vrm(struct device *dev, char *buf) +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, const char *buf, size_t count) +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); @@ -553,7 +553,7 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); #define device_create_file_vrm(client) \ device_create_file(&client->dev, &dev_attr_vrm); -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms)); @@ -564,13 +564,13 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); device_create_file(&client->dev, &dev_attr_alarms) /* 1 PWM */ -static ssize_t show_pwm1(struct device *dev, char *buf) +static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", ASB100_PWM_FROM_REG(data->pwm & 0x0f)); } -static ssize_t set_pwm1(struct device *dev, const char *buf, size_t count) +static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); @@ -584,13 +584,13 @@ static ssize_t set_pwm1(struct device *dev, const char *buf, size_t count) return count; } -static ssize_t show_pwm_enable1(struct device *dev, char *buf) +static ssize_t show_pwm_enable1(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", (data->pwm & 0x80) ? 1 : 0); } -static ssize_t set_pwm_enable1(struct device *dev, const char *buf, +static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); diff --git a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c index bb1fefb..4ae15bd 100644 --- a/drivers/i2c/chips/ds1621.c +++ b/drivers/i2c/chips/ds1621.c @@ -137,7 +137,7 @@ static void ds1621_init_client(struct i2c_client *client) } #define show(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct ds1621_data *data = ds1621_update_client(dev); \ return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ @@ -148,7 +148,7 @@ show(temp_min); show(temp_max); #define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \ +static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -165,7 +165,7 @@ static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \ set_temp(min, temp_min, DS1621_REG_TEMP_MIN); set_temp(max, temp_max, DS1621_REG_TEMP_MAX); -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct ds1621_data *data = ds1621_update_client(dev); return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf)); diff --git a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c index 18e33ac..c3f37db 100644 --- a/drivers/i2c/chips/fscher.c +++ b/drivers/i2c/chips/fscher.c @@ -157,8 +157,8 @@ struct fscher_data { #define sysfs_r(kind, sub, offset, reg) \ static ssize_t show_##kind##sub (struct fscher_data *, char *, int); \ -static ssize_t show_##kind##offset##sub (struct device *, char *); \ -static ssize_t show_##kind##offset##sub (struct device *dev, char *buf) \ +static ssize_t show_##kind##offset##sub (struct device *, struct device_attribute *attr, char *); \ +static ssize_t show_##kind##offset##sub (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct fscher_data *data = fscher_update_device(dev); \ return show_##kind##sub(data, buf, (offset)); \ @@ -166,8 +166,8 @@ static ssize_t show_##kind##offset##sub (struct device *dev, char *buf) \ #define sysfs_w(kind, sub, offset, reg) \ static ssize_t set_##kind##sub (struct i2c_client *, struct fscher_data *, const char *, size_t, int, int); \ -static ssize_t set_##kind##offset##sub (struct device *, const char *, size_t); \ -static ssize_t set_##kind##offset##sub (struct device *dev, const char *buf, size_t count) \ +static ssize_t set_##kind##offset##sub (struct device *, struct device_attribute *attr, const char *, size_t); \ +static ssize_t set_##kind##offset##sub (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct fscher_data *data = i2c_get_clientdata(client); \ diff --git a/drivers/i2c/chips/fscpos.c b/drivers/i2c/chips/fscpos.c index 2cac791..3beaa61 100644 --- a/drivers/i2c/chips/fscpos.c +++ b/drivers/i2c/chips/fscpos.c @@ -245,19 +245,19 @@ static void reset_fan_alarm(struct i2c_client *client, int nr) /* Volts */ #define VOLT_FROM_REG(val, mult) ((val) * (mult) / 255) -static ssize_t show_volt_12(struct device *dev, char *buf) +static ssize_t show_volt_12(struct device *dev, struct device_attribute *attr, char *buf) { struct fscpos_data *data = fscpos_update_device(dev); return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[0], 14200)); } -static ssize_t show_volt_5(struct device *dev, char *buf) +static ssize_t show_volt_5(struct device *dev, struct device_attribute *attr, char *buf) { struct fscpos_data *data = fscpos_update_device(dev); return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[1], 6600)); } -static ssize_t show_volt_batt(struct device *dev, char *buf) +static ssize_t show_volt_batt(struct device *dev, struct device_attribute *attr, char *buf) { struct fscpos_data *data = fscpos_update_device(dev); return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[2], 3300)); @@ -327,7 +327,7 @@ static ssize_t set_wdog_preset(struct i2c_client *client, struct fscpos_data } /* Event */ -static ssize_t show_event(struct device *dev, char *buf) +static ssize_t show_event(struct device *dev, struct device_attribute *attr, char *buf) { /* bits 5..7 reserved => mask with 0x1f */ struct fscpos_data *data = fscpos_update_device(dev); @@ -338,14 +338,14 @@ static ssize_t show_event(struct device *dev, char *buf) * Sysfs stuff */ #define create_getter(kind, sub) \ - static ssize_t sysfs_show_##kind##sub(struct device *dev, char *buf) \ + static ssize_t sysfs_show_##kind##sub(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct fscpos_data *data = fscpos_update_device(dev); \ return show_##kind##sub(data, buf); \ } #define create_getter_n(kind, offset, sub) \ - static ssize_t sysfs_show_##kind##offset##sub(struct device *dev, char\ + static ssize_t sysfs_show_##kind##offset##sub(struct device *dev, struct device_attribute *attr, char\ *buf) \ { \ struct fscpos_data *data = fscpos_update_device(dev); \ @@ -353,7 +353,7 @@ static ssize_t show_event(struct device *dev, char *buf) } #define create_setter(kind, sub, reg) \ - static ssize_t sysfs_set_##kind##sub (struct device *dev, const char \ + static ssize_t sysfs_set_##kind##sub (struct device *dev, struct device_attribute *attr, const char \ *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -362,7 +362,7 @@ static ssize_t show_event(struct device *dev, char *buf) } #define create_setter_n(kind, offset, sub, reg) \ - static ssize_t sysfs_set_##kind##offset##sub (struct device *dev, \ + static ssize_t sysfs_set_##kind##offset##sub (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ diff --git a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c index c82d6ce..4316a15 100644 --- a/drivers/i2c/chips/gl518sm.c +++ b/drivers/i2c/chips/gl518sm.c @@ -164,14 +164,14 @@ static struct i2c_driver gl518_driver = { */ #define show(type, suffix, value) \ -static ssize_t show_##suffix(struct device *dev, char *buf) \ +static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct gl518_data *data = gl518_update_device(dev); \ return sprintf(buf, "%d\n", type##_FROM_REG(data->value)); \ } #define show_fan(suffix, value, index) \ -static ssize_t show_##suffix(struct device *dev, char *buf) \ +static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct gl518_data *data = gl518_update_device(dev); \ return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[index], \ @@ -205,7 +205,7 @@ show(BOOL, beep_enable, beep_enable); show(BEEP_MASK, beep_mask, beep_mask); #define set(type, suffix, value, reg) \ -static ssize_t set_##suffix(struct device *dev, const char *buf, \ +static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -220,7 +220,7 @@ static ssize_t set_##suffix(struct device *dev, const char *buf, \ } #define set_bits(type, suffix, value, reg, mask, shift) \ -static ssize_t set_##suffix(struct device *dev, const char *buf, \ +static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -258,7 +258,7 @@ set_high(IN, in_max3, voltage_max[3], GL518_REG_VIN3_LIMIT); set_bits(BOOL, beep_enable, beep_enable, GL518_REG_CONF, 0x04, 2); set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM); -static ssize_t set_fan_min1(struct device *dev, const char *buf, size_t count) +static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct gl518_data *data = i2c_get_clientdata(client); @@ -284,7 +284,7 @@ static ssize_t set_fan_min1(struct device *dev, const char *buf, size_t count) return count; } -static ssize_t set_fan_min2(struct device *dev, const char *buf, size_t count) +static ssize_t set_fan_min2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct gl518_data *data = i2c_get_clientdata(client); diff --git a/drivers/i2c/chips/gl520sm.c b/drivers/i2c/chips/gl520sm.c index 3fd17e4..a13a504 100644 --- a/drivers/i2c/chips/gl520sm.c +++ b/drivers/i2c/chips/gl520sm.c @@ -148,8 +148,8 @@ struct gl520_data { #define sysfs_r(type, n, item, reg) \ static ssize_t get_##type##item (struct gl520_data *, char *, int); \ -static ssize_t get_##type##n##item (struct device *, char *); \ -static ssize_t get_##type##n##item (struct device *dev, char *buf) \ +static ssize_t get_##type##n##item (struct device *, struct device_attribute *attr, char *); \ +static ssize_t get_##type##n##item (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct gl520_data *data = gl520_update_device(dev); \ return get_##type##item(data, buf, (n)); \ @@ -157,8 +157,8 @@ static ssize_t get_##type##n##item (struct device *dev, char *buf) \ #define sysfs_w(type, n, item, reg) \ static ssize_t set_##type##item (struct i2c_client *, struct gl520_data *, const char *, size_t, int, int); \ -static ssize_t set_##type##n##item (struct device *, const char *, size_t); \ -static ssize_t set_##type##n##item (struct device *dev, const char *buf, size_t count) \ +static ssize_t set_##type##n##item (struct device *, struct device_attribute *attr, const char *, size_t); \ +static ssize_t set_##type##n##item (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct gl520_data *data = i2c_get_clientdata(client); \ diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index cf7e689..007bdf9 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -290,7 +290,7 @@ static ssize_t set_in_max(struct device *dev, const char *buf, #define show_in_offset(offset) \ static ssize_t \ - show_in##offset (struct device *dev, char *buf) \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in(dev, buf, offset); \ } \ @@ -298,21 +298,21 @@ static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); #define limit_in_offset(offset) \ static ssize_t \ - show_in##offset##_min (struct device *dev, char *buf) \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_min(dev, buf, offset); \ } \ static ssize_t \ - show_in##offset##_max (struct device *dev, char *buf) \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_max(dev, buf, offset); \ } \ -static ssize_t set_in##offset##_min (struct device *dev, \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_min(dev, buf, count, offset); \ } \ -static ssize_t set_in##offset##_max (struct device *dev, \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_max(dev, buf, count, offset); \ @@ -383,26 +383,26 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, return count; } #define show_temp_offset(offset) \ -static ssize_t show_temp_##offset (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp(dev, buf, offset - 1); \ } \ static ssize_t \ -show_temp_##offset##_max (struct device *dev, char *buf) \ +show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_max(dev, buf, offset - 1); \ } \ static ssize_t \ -show_temp_##offset##_min (struct device *dev, char *buf) \ +show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_min(dev, buf, offset - 1); \ } \ -static ssize_t set_temp_##offset##_max (struct device *dev, \ +static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_max(dev, buf, count, offset - 1); \ } \ -static ssize_t set_temp_##offset##_min (struct device *dev, \ +static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_min(dev, buf, count, offset - 1); \ @@ -453,11 +453,11 @@ static ssize_t set_sensor(struct device *dev, const char *buf, return count; } #define show_sensor_offset(offset) \ -static ssize_t show_sensor_##offset (struct device *dev, char *buf) \ +static ssize_t show_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_sensor(dev, buf, offset - 1); \ } \ -static ssize_t set_sensor_##offset (struct device *dev, \ +static ssize_t set_sensor_##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_sensor(dev, buf, count, offset - 1); \ @@ -600,24 +600,24 @@ static ssize_t set_pwm(struct device *dev, const char *buf, } #define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_min(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_div(dev, buf, offset - 1); \ } \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_min(dev, buf, count, offset - 1); \ } \ -static ssize_t set_fan_##offset##_div (struct device *dev, \ +static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_div(dev, buf, count, offset - 1); \ @@ -633,21 +633,21 @@ show_fan_offset(2); show_fan_offset(3); #define show_pwm_offset(offset) \ -static ssize_t show_pwm##offset##_enable (struct device *dev, \ +static ssize_t show_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_pwm_enable(dev, buf, offset - 1); \ } \ -static ssize_t show_pwm##offset (struct device *dev, char *buf) \ +static ssize_t show_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_pwm(dev, buf, offset - 1); \ } \ -static ssize_t set_pwm##offset##_enable (struct device *dev, \ +static ssize_t set_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_pwm_enable(dev, buf, count, offset - 1); \ } \ -static ssize_t set_pwm##offset (struct device *dev, \ +static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_pwm(dev, buf, count, offset - 1); \ @@ -663,7 +663,7 @@ show_pwm_offset(2); show_pwm_offset(3); /* Alarms */ -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct it87_data *data = it87_update_device(dev); return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms)); @@ -671,13 +671,13 @@ static ssize_t show_alarms(struct device *dev, char *buf) static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static ssize_t -show_vrm_reg(struct device *dev, char *buf) +show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } static ssize_t -store_vrm_reg(struct device *dev, const char *buf, size_t count) +store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); @@ -693,7 +693,7 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); device_create_file(&client->dev, &dev_attr_vrm) static ssize_t -show_vid_reg(struct device *dev, char *buf) +show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c index 14cc5af..bc68e03 100644 --- a/drivers/i2c/chips/lm63.c +++ b/drivers/i2c/chips/lm63.c @@ -177,7 +177,7 @@ struct lm63_data { */ #define show_fan(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm63_data *data = lm63_update_device(dev); \ return sprintf(buf, "%d\n", FAN_FROM_REG(data->value)); \ @@ -185,7 +185,7 @@ static ssize_t show_##value(struct device *dev, char *buf) \ show_fan(fan1_input); show_fan(fan1_low); -static ssize_t set_fan1_low(struct device *dev, const char *buf, +static ssize_t set_fan1_low(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -202,7 +202,7 @@ static ssize_t set_fan1_low(struct device *dev, const char *buf, return count; } -static ssize_t show_pwm1(struct device *dev, char *buf) +static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? @@ -210,7 +210,7 @@ static ssize_t show_pwm1(struct device *dev, char *buf) (2 * data->pwm1_freq)); } -static ssize_t set_pwm1(struct device *dev, const char *buf, size_t count) +static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); @@ -229,20 +229,20 @@ static ssize_t set_pwm1(struct device *dev, const char *buf, size_t count) return count; } -static ssize_t show_pwm1_enable(struct device *dev, char *buf) +static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *attr, char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); } #define show_temp8(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm63_data *data = lm63_update_device(dev); \ return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->value)); \ } #define show_temp11(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm63_data *data = lm63_update_device(dev); \ return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->value)); \ @@ -255,7 +255,7 @@ show_temp11(temp2_low); show_temp8(temp2_crit); #define set_temp8(value, reg) \ -static ssize_t set_##value(struct device *dev, const char *buf, \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -269,7 +269,7 @@ static ssize_t set_##value(struct device *dev, const char *buf, \ return count; \ } #define set_temp11(value, reg_msb, reg_lsb) \ -static ssize_t set_##value(struct device *dev, const char *buf, \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -289,7 +289,7 @@ set_temp11(temp2_low, LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB); /* Hysteresis register holds a relative value, while we want to present an absolute to user-space */ -static ssize_t show_temp2_crit_hyst(struct device *dev, char *buf) +static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp2_crit) @@ -298,7 +298,7 @@ static ssize_t show_temp2_crit_hyst(struct device *dev, char *buf) /* And now the other way around, user-space provides an absolute hysteresis value and we have to store a relative one */ -static ssize_t set_temp2_crit_hyst(struct device *dev, const char *buf, +static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -314,7 +314,7 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, const char *buf, return count; } -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%u\n", data->alarms); diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c index 0e86cc8..57c51ac 100644 --- a/drivers/i2c/chips/lm75.c +++ b/drivers/i2c/chips/lm75.c @@ -75,7 +75,7 @@ static struct i2c_driver lm75_driver = { }; #define show(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm75_data *data = lm75_update_device(dev); \ return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ @@ -85,7 +85,7 @@ show(temp_hyst); show(temp_input); #define set(value, reg) \ -static ssize_t set_##value(struct device *dev, const char *buf, size_t count) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct lm75_data *data = i2c_get_clientdata(client); \ -- cgit v0.10.2 From 8627f9ba531269d8850919c62af1b017438e2e79 Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:42:03 -0400 Subject: [PATCH] Driver Core: drivers/i2c/chips/lm77.c - max1619.c: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/lm77.c b/drivers/i2c/chips/lm77.c index f56b7a3..9d15cd5 100644 --- a/drivers/i2c/chips/lm77.c +++ b/drivers/i2c/chips/lm77.c @@ -103,7 +103,7 @@ static inline int LM77_TEMP_FROM_REG(u16 reg) /* read routines for temperature limits */ #define show(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm77_data *data = lm77_update_device(dev); \ return sprintf(buf, "%d\n", data->value); \ @@ -116,17 +116,17 @@ show(temp_max); show(alarms); /* read routines for hysteresis values */ -static ssize_t show_temp_crit_hyst(struct device *dev, char *buf) +static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) { struct lm77_data *data = lm77_update_device(dev); return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst); } -static ssize_t show_temp_min_hyst(struct device *dev, char *buf) +static ssize_t show_temp_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) { struct lm77_data *data = lm77_update_device(dev); return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst); } -static ssize_t show_temp_max_hyst(struct device *dev, char *buf) +static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) { struct lm77_data *data = lm77_update_device(dev); return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst); @@ -134,7 +134,7 @@ static ssize_t show_temp_max_hyst(struct device *dev, char *buf) /* write routines */ #define set(value, reg) \ -static ssize_t set_##value(struct device *dev, const char *buf, size_t count) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct lm77_data *data = i2c_get_clientdata(client); \ @@ -152,7 +152,7 @@ set(temp_max, LM77_REG_TEMP_MAX); /* hysteresis is stored as a relative value on the chip, so it has to be converted first */ -static ssize_t set_temp_crit_hyst(struct device *dev, const char *buf, size_t count) +static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm77_data *data = i2c_get_clientdata(client); @@ -167,7 +167,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev, const char *buf, size_t co } /* preserve hysteresis when setting T_crit */ -static ssize_t set_temp_crit(struct device *dev, const char *buf, size_t count) +static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm77_data *data = i2c_get_clientdata(client); diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c index 6d52d14..21b195f 100644 --- a/drivers/i2c/chips/lm78.c +++ b/drivers/i2c/chips/lm78.c @@ -224,28 +224,28 @@ static ssize_t set_in_max(struct device *dev, const char *buf, #define show_in_offset(offset) \ static ssize_t \ - show_in##offset (struct device *dev, char *buf) \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in(dev, buf, offset); \ } \ static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ show_in##offset, NULL); \ static ssize_t \ - show_in##offset##_min (struct device *dev, char *buf) \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_min(dev, buf, offset); \ } \ static ssize_t \ - show_in##offset##_max (struct device *dev, char *buf) \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_max(dev, buf, offset); \ } \ -static ssize_t set_in##offset##_min (struct device *dev, \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_min(dev, buf, count, offset); \ } \ -static ssize_t set_in##offset##_max (struct device *dev, \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_max(dev, buf, count, offset); \ @@ -264,19 +264,19 @@ show_in_offset(5); show_in_offset(6); /* Temperature */ -static ssize_t show_temp(struct device *dev, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); } -static ssize_t show_temp_over(struct device *dev, char *buf) +static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); } -static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count) +static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm78_data *data = i2c_get_clientdata(client); @@ -289,13 +289,13 @@ static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count) return count; } -static ssize_t show_temp_hyst(struct device *dev, char *buf) +static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); } -static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count) +static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm78_data *data = i2c_get_clientdata(client); @@ -398,19 +398,19 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, } #define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_min(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_div(dev, buf, offset - 1); \ } \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_min(dev, buf, count, offset - 1); \ @@ -419,13 +419,13 @@ static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ show_fan_##offset##_min, set_fan_##offset##_min); -static ssize_t set_fan_1_div(struct device *dev, const char *buf, +static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { return set_fan_div(dev, buf, count, 0) ; } -static ssize_t set_fan_2_div(struct device *dev, const char *buf, +static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { return set_fan_div(dev, buf, count, 1) ; @@ -443,7 +443,7 @@ static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL); /* VID */ -static ssize_t show_vid(struct device *dev, char *buf) +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", VID_FROM_REG(data->vid)); @@ -451,7 +451,7 @@ static ssize_t show_vid(struct device *dev, char *buf) static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); /* Alarms */ -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%u\n", data->alarms); diff --git a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c index a72f431..404057b 100644 --- a/drivers/i2c/chips/lm80.c +++ b/drivers/i2c/chips/lm80.c @@ -156,7 +156,7 @@ static struct i2c_driver lm80_driver = { */ #define show_in(suffix, value) \ -static ssize_t show_in_##suffix(struct device *dev, char *buf) \ +static ssize_t show_in_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm80_data *data = lm80_update_device(dev); \ return sprintf(buf, "%d\n", IN_FROM_REG(data->value)); \ @@ -184,7 +184,7 @@ show_in(input5, in[5]); show_in(input6, in[6]); #define set_in(suffix, value, reg) \ -static ssize_t set_in_##suffix(struct device *dev, const char *buf, \ +static ssize_t set_in_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -213,7 +213,7 @@ set_in(max5, in_max[5], LM80_REG_IN_MAX(5)); set_in(max6, in_max[6], LM80_REG_IN_MAX(6)); #define show_fan(suffix, value, div) \ -static ssize_t show_fan_##suffix(struct device *dev, char *buf) \ +static ssize_t show_fan_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm80_data *data = lm80_update_device(dev); \ return sprintf(buf, "%d\n", FAN_FROM_REG(data->value, \ @@ -225,7 +225,7 @@ show_fan(input1, fan[0], fan_div[0]); show_fan(input2, fan[1], fan_div[1]); #define show_fan_div(suffix, value) \ -static ssize_t show_fan_div##suffix(struct device *dev, char *buf) \ +static ssize_t show_fan_div##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm80_data *data = lm80_update_device(dev); \ return sprintf(buf, "%d\n", DIV_FROM_REG(data->value)); \ @@ -234,7 +234,7 @@ show_fan_div(1, fan_div[0]); show_fan_div(2, fan_div[1]); #define set_fan(suffix, value, reg, div) \ -static ssize_t set_fan_##suffix(struct device *dev, const char *buf, \ +static ssize_t set_fan_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -292,7 +292,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, } #define set_fan_div(number) \ -static ssize_t set_fan_div##number(struct device *dev, const char *buf, \ +static ssize_t set_fan_div##number(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ return set_fan_div(dev, buf, count, number - 1); \ @@ -300,14 +300,14 @@ static ssize_t set_fan_div##number(struct device *dev, const char *buf, \ set_fan_div(1); set_fan_div(2); -static ssize_t show_temp_input1(struct device *dev, char *buf) +static ssize_t show_temp_input1(struct device *dev, struct device_attribute *attr, char *buf) { struct lm80_data *data = lm80_update_device(dev); return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp)); } #define show_temp(suffix, value) \ -static ssize_t show_temp_##suffix(struct device *dev, char *buf) \ +static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm80_data *data = lm80_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \ @@ -318,7 +318,7 @@ show_temp(os_max, temp_os_max); show_temp(os_hyst, temp_os_hyst); #define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \ +static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -336,7 +336,7 @@ set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST); set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX); set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST); -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm80_data *data = lm80_update_device(dev); return sprintf(buf, "%u\n", data->alarms); diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c index 3dafe60..4d6d7d2 100644 --- a/drivers/i2c/chips/lm83.c +++ b/drivers/i2c/chips/lm83.c @@ -155,7 +155,7 @@ struct lm83_data { */ #define show_temp(suffix, value) \ -static ssize_t show_temp_##suffix(struct device *dev, char *buf) \ +static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm83_data *data = lm83_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ @@ -171,7 +171,7 @@ show_temp(high4, temp_high[3]); show_temp(crit, temp_crit); #define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \ +static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -190,7 +190,7 @@ set_temp(high3, temp_high[2], LM83_REG_W_REMOTE2_HIGH); set_temp(high4, temp_high[3], LM83_REG_W_REMOTE3_HIGH); set_temp(crit, temp_crit, LM83_REG_W_TCRIT); -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm83_data *data = lm83_update_device(dev); return sprintf(buf, "%d\n", data->alarms); diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c index b1a0dc5..b197677 100644 --- a/drivers/i2c/chips/lm85.c +++ b/drivers/i2c/chips/lm85.c @@ -426,15 +426,15 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, } #define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_min(dev, buf, offset - 1); \ } \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_min(dev, buf, count, offset - 1); \ @@ -451,7 +451,7 @@ show_fan_offset(4); /* vid, vrm, alarms */ -static ssize_t show_vid_reg(struct device *dev, char *buf) +static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); @@ -459,13 +459,13 @@ static ssize_t show_vid_reg(struct device *dev, char *buf) static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -static ssize_t show_vrm_reg(struct device *dev, char *buf) +static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } -static ssize_t store_vrm_reg(struct device *dev, const char *buf, size_t count) +static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); @@ -478,7 +478,7 @@ static ssize_t store_vrm_reg(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -static ssize_t show_alarms_reg(struct device *dev, char *buf) +static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms)); @@ -516,16 +516,16 @@ static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) } #define show_pwm_reg(offset) \ -static ssize_t show_pwm_##offset (struct device *dev, char *buf) \ +static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_pwm(dev, buf, offset - 1); \ } \ -static ssize_t set_pwm_##offset (struct device *dev, \ +static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_pwm(dev, buf, count, offset - 1); \ } \ -static ssize_t show_pwm_enable##offset (struct device *dev, char *buf) \ +static ssize_t show_pwm_enable##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_pwm_enable(dev, buf, offset - 1); \ } \ @@ -585,24 +585,24 @@ static ssize_t set_in_max(struct device *dev, const char *buf, return count; } #define show_in_reg(offset) \ -static ssize_t show_in_##offset (struct device *dev, char *buf) \ +static ssize_t show_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in(dev, buf, offset); \ } \ -static ssize_t show_in_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_in_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_min(dev, buf, offset); \ } \ -static ssize_t show_in_##offset##_max (struct device *dev, char *buf) \ +static ssize_t show_in_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_max(dev, buf, offset); \ } \ -static ssize_t set_in_##offset##_min (struct device *dev, \ +static ssize_t set_in_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_min(dev, buf, count, offset); \ } \ -static ssize_t set_in_##offset##_max (struct device *dev, \ +static ssize_t set_in_##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_max(dev, buf, count, offset); \ @@ -666,24 +666,24 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, return count; } #define show_temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp(dev, buf, offset - 1); \ } \ -static ssize_t show_temp_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_min(dev, buf, offset - 1); \ } \ -static ssize_t show_temp_##offset##_max (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_max(dev, buf, offset - 1); \ } \ -static ssize_t set_temp_##offset##_min (struct device *dev, \ +static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_min(dev, buf, count, offset - 1); \ } \ -static ssize_t set_temp_##offset##_max (struct device *dev, \ +static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_max(dev, buf, count, offset - 1); \ @@ -786,42 +786,42 @@ static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf, return count; } #define pwm_auto(offset) \ -static ssize_t show_pwm##offset##_auto_channels (struct device *dev, \ +static ssize_t show_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_pwm_auto_channels(dev, buf, offset - 1); \ } \ -static ssize_t set_pwm##offset##_auto_channels (struct device *dev, \ +static ssize_t set_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_pwm_auto_channels(dev, buf, count, offset - 1); \ } \ -static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, \ +static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_pwm_auto_pwm_min(dev, buf, offset - 1); \ } \ -static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, \ +static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_pwm_auto_pwm_min(dev, buf, count, offset - 1); \ } \ -static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, \ +static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_pwm_auto_pwm_minctl(dev, buf, offset - 1); \ } \ -static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, \ +static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_pwm_auto_pwm_minctl(dev, buf, count, offset - 1); \ } \ -static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, \ +static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_pwm_auto_pwm_freq(dev, buf, offset - 1); \ } \ -static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, \ +static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_pwm_auto_pwm_freq(dev, buf, count, offset - 1); \ @@ -962,42 +962,42 @@ static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf, return count; } #define temp_auto(offset) \ -static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, \ +static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_temp_auto_temp_off(dev, buf, offset - 1); \ } \ -static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, \ +static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_auto_temp_off(dev, buf, count, offset - 1); \ } \ -static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, \ +static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_temp_auto_temp_min(dev, buf, offset - 1); \ } \ -static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, \ +static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_auto_temp_min(dev, buf, count, offset - 1); \ } \ -static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, \ +static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_temp_auto_temp_max(dev, buf, offset - 1); \ } \ -static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, \ +static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_auto_temp_max(dev, buf, count, offset - 1); \ } \ -static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, \ +static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return show_temp_auto_temp_crit(dev, buf, offset - 1); \ } \ -static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, \ +static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_auto_temp_crit(dev, buf, count, offset - 1); \ diff --git a/drivers/i2c/chips/lm87.c b/drivers/i2c/chips/lm87.c index 98cabd6..4372b61 100644 --- a/drivers/i2c/chips/lm87.c +++ b/drivers/i2c/chips/lm87.c @@ -218,19 +218,19 @@ static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) } #define show_in(offset) \ -static ssize_t show_in##offset##_input(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm87_data *data = lm87_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ data->in_scale[offset])); \ } \ -static ssize_t show_in##offset##_min(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm87_data *data = lm87_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ data->in_scale[offset])); \ } \ -static ssize_t show_in##offset##_max(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm87_data *data = lm87_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ @@ -274,13 +274,13 @@ static void set_in_max(struct device *dev, const char *buf, int nr) } #define set_in(offset) \ -static ssize_t set_in##offset##_min(struct device *dev, \ +static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ set_in_min(dev, buf, offset); \ return count; \ } \ -static ssize_t set_in##offset##_max(struct device *dev, \ +static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ set_in_max(dev, buf, offset); \ @@ -300,17 +300,17 @@ set_in(6); set_in(7); #define show_temp(offset) \ -static ssize_t show_temp##offset##_input(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm87_data *data = lm87_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ } \ -static ssize_t show_temp##offset##_low(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_low(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm87_data *data = lm87_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[offset-1])); \ } \ -static ssize_t show_temp##offset##_high(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_high(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm87_data *data = lm87_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[offset-1])); \ @@ -346,13 +346,13 @@ static void set_temp_high(struct device *dev, const char *buf, int nr) } #define set_temp(offset) \ -static ssize_t set_temp##offset##_low(struct device *dev, \ +static ssize_t set_temp##offset##_low(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ set_temp_low(dev, buf, offset-1); \ return count; \ } \ -static ssize_t set_temp##offset##_high(struct device *dev, \ +static ssize_t set_temp##offset##_high(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ set_temp_high(dev, buf, offset-1); \ @@ -366,13 +366,13 @@ set_temp(1); set_temp(2); set_temp(3); -static ssize_t show_temp_crit_int(struct device *dev, char *buf) +static ssize_t show_temp_crit_int(struct device *dev, struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int)); } -static ssize_t show_temp_crit_ext(struct device *dev, char *buf) +static ssize_t show_temp_crit_ext(struct device *dev, struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext)); @@ -383,19 +383,19 @@ static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL); static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL); #define show_fan(offset) \ -static ssize_t show_fan##offset##_input(struct device *dev, char *buf) \ +static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm87_data *data = lm87_update_device(dev); \ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[offset-1], \ FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ } \ -static ssize_t show_fan##offset##_min(struct device *dev, char *buf) \ +static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm87_data *data = lm87_update_device(dev); \ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[offset-1], \ FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ } \ -static ssize_t show_fan##offset##_div(struct device *dev, char *buf) \ +static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm87_data *data = lm87_update_device(dev); \ return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[offset-1])); \ @@ -465,13 +465,13 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, } #define set_fan(offset) \ -static ssize_t set_fan##offset##_min(struct device *dev, const char *buf, \ +static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ set_fan_min(dev, buf, offset-1); \ return count; \ } \ -static ssize_t set_fan##offset##_div(struct device *dev, const char *buf, \ +static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ return set_fan_div(dev, buf, count, offset-1); \ @@ -483,26 +483,26 @@ static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ set_fan(1); set_fan(2); -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static ssize_t show_vid(struct device *dev, char *buf) +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); -static ssize_t show_vrm(struct device *dev, char *buf) +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, const char *buf, size_t count) +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); @@ -511,12 +511,12 @@ static ssize_t set_vrm(struct device *dev, const char *buf, size_t count) } static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); -static ssize_t show_aout(struct device *dev, char *buf) +static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); } -static ssize_t set_aout(struct device *dev, const char *buf, size_t count) +static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c index 2c00ff8..9b127a0 100644 --- a/drivers/i2c/chips/lm90.c +++ b/drivers/i2c/chips/lm90.c @@ -218,7 +218,7 @@ struct lm90_data { */ #define show_temp(value, converter) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm90_data *data = lm90_update_device(dev); \ return sprintf(buf, "%d\n", converter(data->value)); \ @@ -233,7 +233,7 @@ show_temp(temp_crit1, TEMP1_FROM_REG); show_temp(temp_crit2, TEMP1_FROM_REG); #define set_temp1(value, reg) \ -static ssize_t set_##value(struct device *dev, const char *buf, \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -250,7 +250,7 @@ static ssize_t set_##value(struct device *dev, const char *buf, \ return count; \ } #define set_temp2(value, regh, regl) \ -static ssize_t set_##value(struct device *dev, const char *buf, \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -275,7 +275,7 @@ set_temp1(temp_crit1, LM90_REG_W_LOCAL_CRIT); set_temp1(temp_crit2, LM90_REG_W_REMOTE_CRIT); #define show_temp_hyst(value, basereg) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm90_data *data = lm90_update_device(dev); \ return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->basereg) \ @@ -284,7 +284,7 @@ static ssize_t show_##value(struct device *dev, char *buf) \ show_temp_hyst(temp_hyst1, temp_crit1); show_temp_hyst(temp_hyst2, temp_crit2); -static ssize_t set_temp_hyst1(struct device *dev, const char *buf, +static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -300,7 +300,7 @@ static ssize_t set_temp_hyst1(struct device *dev, const char *buf, return count; } -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm90_data *data = lm90_update_device(dev); return sprintf(buf, "%d\n", data->alarms); diff --git a/drivers/i2c/chips/lm92.c b/drivers/i2c/chips/lm92.c index fe6e83d..215c8e4 100644 --- a/drivers/i2c/chips/lm92.c +++ b/drivers/i2c/chips/lm92.c @@ -140,7 +140,7 @@ static struct lm92_data *lm92_update_device(struct device *dev) } #define show_temp(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct lm92_data *data = lm92_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ @@ -151,7 +151,7 @@ show_temp(temp1_min); show_temp(temp1_max); #define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, const char *buf, \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -168,26 +168,26 @@ set_temp(temp1_crit, LM92_REG_TEMP_CRIT); set_temp(temp1_min, LM92_REG_TEMP_LOW); set_temp(temp1_max, LM92_REG_TEMP_HIGH); -static ssize_t show_temp1_crit_hyst(struct device *dev, char *buf) +static ssize_t show_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit) - TEMP_FROM_REG(data->temp1_hyst)); } -static ssize_t show_temp1_max_hyst(struct device *dev, char *buf) +static ssize_t show_temp1_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max) - TEMP_FROM_REG(data->temp1_hyst)); } -static ssize_t show_temp1_min_hyst(struct device *dev, char *buf) +static ssize_t show_temp1_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min) + TEMP_FROM_REG(data->temp1_hyst)); } -static ssize_t set_temp1_crit_hyst(struct device *dev, const char *buf, +static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -202,7 +202,7 @@ static ssize_t set_temp1_crit_hyst(struct device *dev, const char *buf, return count; } -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input)); diff --git a/drivers/i2c/chips/max1619.c b/drivers/i2c/chips/max1619.c index 5afa961..30a1961 100644 --- a/drivers/i2c/chips/max1619.c +++ b/drivers/i2c/chips/max1619.c @@ -122,7 +122,7 @@ struct max1619_data { */ #define show_temp(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct max1619_data *data = max1619_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ @@ -135,7 +135,7 @@ show_temp(temp_crit2); show_temp(temp_hyst2); #define set_temp2(value, reg) \ -static ssize_t set_##value(struct device *dev, const char *buf, \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -154,7 +154,7 @@ set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH); set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT); set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST); -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct max1619_data *data = max1619_update_device(dev); return sprintf(buf, "%d\n", data->alarms); -- cgit v0.10.2 From a5099cfc2e82240b0a3e72ad79a5969d5af1a7dc Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:42:25 -0400 Subject: [PATCH] Driver Core: drivers/i2c/chips/pc87360.c - w83627hf.c: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/pc87360.c b/drivers/i2c/chips/pc87360.c index 6d94c36..65637b2 100644 --- a/drivers/i2c/chips/pc87360.c +++ b/drivers/i2c/chips/pc87360.c @@ -282,31 +282,31 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, } #define show_and_set_fan(offset) \ -static ssize_t show_fan##offset##_input(struct device *dev, char *buf) \ +static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[offset-1], \ FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \ } \ -static ssize_t show_fan##offset##_min(struct device *dev, char *buf) \ +static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[offset-1], \ FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \ } \ -static ssize_t show_fan##offset##_div(struct device *dev, char *buf) \ +static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", \ FAN_DIV_FROM_REG(data->fan_status[offset-1])); \ } \ -static ssize_t show_fan##offset##_status(struct device *dev, char *buf) \ +static ssize_t show_fan##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", \ FAN_STATUS_FROM_REG(data->fan_status[offset-1])); \ } \ -static ssize_t set_fan##offset##_min(struct device *dev, const char *buf, \ +static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ return set_fan_min(dev, buf, count, offset-1); \ @@ -324,7 +324,7 @@ show_and_set_fan(2) show_and_set_fan(3) #define show_and_set_pwm(offset) \ -static ssize_t show_pwm##offset(struct device *dev, char *buf) \ +static ssize_t show_pwm##offset(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", \ @@ -332,7 +332,7 @@ static ssize_t show_pwm##offset(struct device *dev, char *buf) \ FAN_CONFIG_INVERT(data->fan_conf, \ offset-1))); \ } \ -static ssize_t set_pwm##offset(struct device *dev, const char *buf, \ +static ssize_t set_pwm##offset(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -354,30 +354,30 @@ show_and_set_pwm(2) show_and_set_pwm(3) #define show_and_set_in(offset) \ -static ssize_t show_in##offset##_input(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ data->in_vref)); \ } \ -static ssize_t show_in##offset##_min(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ data->in_vref)); \ } \ -static ssize_t show_in##offset##_max(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ data->in_vref)); \ } \ -static ssize_t show_in##offset##_status(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", data->in_status[offset]); \ } \ -static ssize_t set_in##offset##_min(struct device *dev, const char *buf, \ +static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -391,7 +391,7 @@ static ssize_t set_in##offset##_min(struct device *dev, const char *buf, \ up(&data->update_lock); \ return count; \ } \ -static ssize_t set_in##offset##_max(struct device *dev, const char *buf, \ +static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -427,36 +427,36 @@ show_and_set_in(9) show_and_set_in(10) #define show_and_set_therm(offset) \ -static ssize_t show_temp##offset##_input(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset+7], \ data->in_vref)); \ } \ -static ssize_t show_temp##offset##_min(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset+7], \ data->in_vref)); \ } \ -static ssize_t show_temp##offset##_max(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset+7], \ data->in_vref)); \ } \ -static ssize_t show_temp##offset##_crit(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[offset-4], \ data->in_vref)); \ } \ -static ssize_t show_temp##offset##_status(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%u\n", data->in_status[offset+7]); \ } \ -static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \ +static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -470,7 +470,7 @@ static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \ up(&data->update_lock); \ return count; \ } \ -static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \ +static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -484,7 +484,7 @@ static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \ up(&data->update_lock); \ return count; \ } \ -static ssize_t set_temp##offset##_crit(struct device *dev, const char *buf, \ +static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -512,19 +512,19 @@ show_and_set_therm(4) show_and_set_therm(5) show_and_set_therm(6) -static ssize_t show_vid(struct device *dev, char *buf) +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); -static ssize_t show_vrm(struct device *dev, char *buf) +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, const char *buf, size_t count) +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct pc87360_data *data = i2c_get_clientdata(client); @@ -533,7 +533,7 @@ static ssize_t set_vrm(struct device *dev, const char *buf, size_t count) } static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); -static ssize_t show_in_alarms(struct device *dev, char *buf) +static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", data->in_alarms); @@ -541,32 +541,32 @@ static ssize_t show_in_alarms(struct device *dev, char *buf) static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); #define show_and_set_temp(offset) \ -static ssize_t show_temp##offset##_input(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ } \ -static ssize_t show_temp##offset##_min(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ } \ -static ssize_t show_temp##offset##_max(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ }\ -static ssize_t show_temp##offset##_crit(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[offset-1])); \ }\ -static ssize_t show_temp##offset##_status(struct device *dev, char *buf) \ +static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pc87360_data *data = pc87360_update_device(dev); \ return sprintf(buf, "%d\n", data->temp_status[offset-1]); \ }\ -static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \ +static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -580,7 +580,7 @@ static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \ up(&data->update_lock); \ return count; \ } \ -static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \ +static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -594,7 +594,7 @@ static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \ up(&data->update_lock); \ return count; \ } \ -static ssize_t set_temp##offset##_crit(struct device *dev, const char *buf, \ +static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ @@ -622,7 +622,7 @@ show_and_set_temp(1) show_and_set_temp(2) show_and_set_temp(3) -static ssize_t show_temp_alarms(struct device *dev, char *buf) +static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", data->temp_alarms); diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 48b4e22..4956e9e 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -76,7 +76,7 @@ static struct i2c_driver pcf8574_driver = { }; /* following are the sysfs callback functions */ -static ssize_t show_read(struct device *dev, char *buf) +static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct pcf8574_data *data = i2c_get_clientdata(client); @@ -86,13 +86,13 @@ static ssize_t show_read(struct device *dev, char *buf) static DEVICE_ATTR(read, S_IRUGO, show_read, NULL); -static ssize_t show_write(struct device *dev, char *buf) +static ssize_t show_write(struct device *dev, struct device_attribute *attr, char *buf) { struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev)); return sprintf(buf, "%u\n", data->write); } -static ssize_t set_write(struct device *dev, const char *buf, +static ssize_t set_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index b6b927d..db812ad 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -100,7 +100,7 @@ static struct i2c_driver pcf8591_driver = { /* following are the sysfs callback functions */ #define show_in_channel(channel) \ -static ssize_t show_in##channel##_input(struct device *dev, char *buf) \ +static ssize_t show_in##channel##_input(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\ } \ @@ -112,13 +112,13 @@ show_in_channel(1); show_in_channel(2); show_in_channel(3); -static ssize_t show_out0_ouput(struct device *dev, char *buf) +static ssize_t show_out0_ouput(struct device *dev, struct device_attribute *attr, char *buf) { struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); return sprintf(buf, "%d\n", data->aout * 10); } -static ssize_t set_out0_output(struct device *dev, const char *buf, size_t count) +static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned int value; struct i2c_client *client = to_i2c_client(dev); @@ -134,13 +134,13 @@ static ssize_t set_out0_output(struct device *dev, const char *buf, size_t count static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, show_out0_ouput, set_out0_output); -static ssize_t show_out0_enable(struct device *dev, char *buf) +static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf) { struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF))); } -static ssize_t set_out0_enable(struct device *dev, const char *buf, size_t count) +static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct pcf8591_data *data = i2c_get_clientdata(client); diff --git a/drivers/i2c/chips/sis5595.c b/drivers/i2c/chips/sis5595.c index 7ea8453..c665072 100644 --- a/drivers/i2c/chips/sis5595.c +++ b/drivers/i2c/chips/sis5595.c @@ -256,28 +256,28 @@ static ssize_t set_in_max(struct device *dev, const char *buf, #define show_in_offset(offset) \ static ssize_t \ - show_in##offset (struct device *dev, char *buf) \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in(dev, buf, offset); \ } \ static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ show_in##offset, NULL); \ static ssize_t \ - show_in##offset##_min (struct device *dev, char *buf) \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_min(dev, buf, offset); \ } \ static ssize_t \ - show_in##offset##_max (struct device *dev, char *buf) \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_max(dev, buf, offset); \ } \ -static ssize_t set_in##offset##_min (struct device *dev, \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_min(dev, buf, count, offset); \ } \ -static ssize_t set_in##offset##_max (struct device *dev, \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_max(dev, buf, count, offset); \ @@ -294,19 +294,19 @@ show_in_offset(3); show_in_offset(4); /* Temperature */ -static ssize_t show_temp(struct device *dev, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); } -static ssize_t show_temp_over(struct device *dev, char *buf) +static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); } -static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count) +static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct sis5595_data *data = i2c_get_clientdata(client); @@ -319,13 +319,13 @@ static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count) return count; } -static ssize_t show_temp_hyst(struct device *dev, char *buf) +static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); } -static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count) +static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct sis5595_data *data = i2c_get_clientdata(client); @@ -426,19 +426,19 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, } #define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_min(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_div(dev, buf, offset - 1); \ } \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_min(dev, buf, count, offset - 1); \ @@ -450,13 +450,13 @@ static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ show_fan_offset(1); show_fan_offset(2); -static ssize_t set_fan_1_div(struct device *dev, const char *buf, +static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { return set_fan_div(dev, buf, count, 0) ; } -static ssize_t set_fan_2_div(struct device *dev, const char *buf, +static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { return set_fan_div(dev, buf, count, 1) ; @@ -467,7 +467,7 @@ static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_2_div, set_fan_2_div); /* Alarms */ -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", data->alarms); diff --git a/drivers/i2c/chips/smsc47b397.c b/drivers/i2c/chips/smsc47b397.c index 1119c76..251ac26 100644 --- a/drivers/i2c/chips/smsc47b397.c +++ b/drivers/i2c/chips/smsc47b397.c @@ -172,7 +172,7 @@ static ssize_t show_temp(struct device *dev, char *buf, int nr) } #define sysfs_temp(num) \ -static ssize_t show_temp##num(struct device *dev, char *buf) \ +static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp(dev, buf, num-1); \ } \ @@ -201,7 +201,7 @@ static ssize_t show_fan(struct device *dev, char *buf, int nr) } #define sysfs_fan(num) \ -static ssize_t show_fan##num(struct device *dev, char *buf) \ +static ssize_t show_fan##num(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, num-1); \ } \ diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c index 0e12ca3..13d6d4a 100644 --- a/drivers/i2c/chips/smsc47m1.c +++ b/drivers/i2c/chips/smsc47m1.c @@ -184,7 +184,7 @@ static ssize_t get_pwm_en(struct device *dev, char *buf, int nr) return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr])); } -static ssize_t get_alarms(struct device *dev, char *buf) +static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); return sprintf(buf, "%d\n", data->alarms); @@ -298,42 +298,42 @@ static ssize_t set_pwm_en(struct device *dev, const char *buf, } #define fan_present(offset) \ -static ssize_t get_fan##offset (struct device *dev, char *buf) \ +static ssize_t get_fan##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return get_fan(dev, buf, offset - 1); \ } \ -static ssize_t get_fan##offset##_min (struct device *dev, char *buf) \ +static ssize_t get_fan##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return get_fan_min(dev, buf, offset - 1); \ } \ -static ssize_t set_fan##offset##_min (struct device *dev, \ +static ssize_t set_fan##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_min(dev, buf, count, offset - 1); \ } \ -static ssize_t get_fan##offset##_div (struct device *dev, char *buf) \ +static ssize_t get_fan##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return get_fan_div(dev, buf, offset - 1); \ } \ -static ssize_t set_fan##offset##_div (struct device *dev, \ +static ssize_t set_fan##offset##_div (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_div(dev, buf, count, offset - 1); \ } \ -static ssize_t get_pwm##offset (struct device *dev, char *buf) \ +static ssize_t get_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return get_pwm(dev, buf, offset - 1); \ } \ -static ssize_t set_pwm##offset (struct device *dev, \ +static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_pwm(dev, buf, count, offset - 1); \ } \ -static ssize_t get_pwm##offset##_en (struct device *dev, char *buf) \ +static ssize_t get_pwm##offset##_en (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return get_pwm_en(dev, buf, offset - 1); \ } \ -static ssize_t set_pwm##offset##_en (struct device *dev, \ +static ssize_t set_pwm##offset##_en (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_pwm_en(dev, buf, count, offset - 1); \ diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index 6614a59..fefc24a 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -386,26 +386,26 @@ static ssize_t set_in_max(struct device *dev, const char *buf, } #define show_in_offset(offset) \ static ssize_t \ - show_in##offset (struct device *dev, char *buf) \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in(dev, buf, offset); \ } \ static ssize_t \ - show_in##offset##_min (struct device *dev, char *buf) \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_min(dev, buf, offset); \ } \ static ssize_t \ - show_in##offset##_max (struct device *dev, char *buf) \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_max(dev, buf, offset); \ } \ -static ssize_t set_in##offset##_min (struct device *dev, \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_min(dev, buf, count, offset); \ } \ -static ssize_t set_in##offset##_max (struct device *dev, \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_in_max(dev, buf, count, offset); \ @@ -460,26 +460,26 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf, return count; } #define show_temp_offset(offset) \ -static ssize_t show_temp_##offset (struct device *dev, char *buf) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp(dev, buf, offset - 1); \ } \ static ssize_t \ -show_temp_##offset##_over (struct device *dev, char *buf) \ +show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_over(dev, buf, offset - 1); \ } \ static ssize_t \ -show_temp_##offset##_hyst (struct device *dev, char *buf) \ +show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_hyst(dev, buf, offset - 1); \ } \ -static ssize_t set_temp_##offset##_over (struct device *dev, \ +static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_over(dev, buf, count, offset - 1); \ } \ -static ssize_t set_temp_##offset##_hyst (struct device *dev, \ +static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_temp_hyst(dev, buf, count, offset - 1); \ @@ -538,24 +538,24 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, } #define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_min(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_div(dev, buf, offset - 1); \ } \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_min(dev, buf, count, offset - 1); \ } \ -static ssize_t set_fan_##offset##_div (struct device *dev, \ +static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return set_fan_div(dev, buf, count, offset - 1); \ @@ -570,7 +570,7 @@ show_fan_offset(1); show_fan_offset(2); /* Alarms */ -static ssize_t show_alarms(struct device *dev, char *buf) { +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms)); } diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index b1da5ed..4f1bff5 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -368,19 +368,19 @@ store_in_reg(MAX, max) #define sysfs_in_offset(offset) \ static ssize_t \ -show_regs_in_##offset (struct device *dev, char *buf) \ +show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in(dev, buf, offset); \ } \ static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); #define sysfs_in_reg_offset(reg, offset) \ -static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_##reg (dev, buf, offset); \ } \ static ssize_t \ -store_regs_in_##reg##offset (struct device *dev, \ +store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return store_in_##reg (dev, buf, count, offset); \ @@ -419,25 +419,25 @@ static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) return sprintf(buf,"%ld\n", in0); } -static ssize_t show_regs_in_0(struct device *dev, char *buf) +static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return show_in_0(data, buf, data->in[0]); } -static ssize_t show_regs_in_min0(struct device *dev, char *buf) +static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return show_in_0(data, buf, data->in_min[0]); } -static ssize_t show_regs_in_max0(struct device *dev, char *buf) +static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return show_in_0(data, buf, data->in_max[0]); } -static ssize_t store_regs_in_min0(struct device *dev, +static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -462,7 +462,7 @@ static ssize_t store_regs_in_min0(struct device *dev, return count; } -static ssize_t store_regs_in_max0(struct device *dev, +static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -531,19 +531,19 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr) } #define sysfs_fan_offset(offset) \ -static ssize_t show_regs_fan_##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, offset); \ } \ static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); #define sysfs_fan_min_offset(offset) \ -static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_min(dev, buf, offset); \ } \ static ssize_t \ -store_regs_fan_min##offset (struct device *dev, const char *buf, size_t count) \ +store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ return store_fan_min(dev, buf, count, offset); \ } \ @@ -608,19 +608,19 @@ store_temp_reg(HYST, max_hyst); #define sysfs_temp_offset(offset) \ static ssize_t \ -show_regs_temp_##offset (struct device *dev, char *buf) \ +show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp(dev, buf, offset); \ } \ static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); #define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_##reg (dev, buf, offset); \ } \ static ssize_t \ -store_regs_temp_##reg##offset (struct device *dev, \ +store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return store_temp_##reg (dev, buf, count, offset); \ @@ -645,7 +645,7 @@ device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ } while (0) static ssize_t -show_vid_reg(struct device *dev, char *buf) +show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); @@ -655,13 +655,13 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); device_create_file(&client->dev, &dev_attr_cpu0_vid) static ssize_t -show_vrm_reg(struct device *dev, char *buf) +show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } static ssize_t -store_vrm_reg(struct device *dev, const char *buf, size_t count) +store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct w83627hf_data *data = i2c_get_clientdata(client); @@ -677,7 +677,7 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); device_create_file(&client->dev, &dev_attr_vrm) static ssize_t -show_alarms_reg(struct device *dev, char *buf) +show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long) data->alarms); @@ -687,7 +687,7 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); device_create_file(&client->dev, &dev_attr_alarms) #define show_beep_reg(REG, reg) \ -static ssize_t show_beep_##reg (struct device *dev, char *buf) \ +static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct w83627hf_data *data = w83627hf_update_device(dev); \ return sprintf(buf,"%ld\n", \ @@ -732,12 +732,12 @@ store_beep_reg(struct device *dev, const char *buf, size_t count, } #define sysfs_beep(REG, reg) \ -static ssize_t show_regs_beep_##reg (struct device *dev, char *buf) \ +static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ { \ - return show_beep_##reg(dev, buf); \ + return show_beep_##reg(dev, attr, buf); \ } \ static ssize_t \ -store_regs_beep_##reg (struct device *dev, const char *buf, size_t count) \ +store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ return store_beep_reg(dev, buf, count, BEEP_##REG); \ } \ @@ -801,12 +801,12 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) } #define sysfs_fan_div(offset) \ -static ssize_t show_regs_fan_div_##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_div_reg(dev, buf, offset); \ } \ static ssize_t \ -store_regs_fan_div_##offset (struct device *dev, \ +store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return store_fan_div_reg(dev, buf, count, offset - 1); \ @@ -861,12 +861,12 @@ store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) } #define sysfs_pwm(offset) \ -static ssize_t show_regs_pwm_##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_pwm_reg(dev, buf, offset); \ } \ static ssize_t \ -store_regs_pwm_##offset (struct device *dev, const char *buf, size_t count) \ +store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ return store_pwm_reg(dev, buf, count, offset); \ } \ @@ -937,12 +937,12 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) } #define sysfs_sensor(offset) \ -static ssize_t show_regs_sensor_##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_sensor_reg(dev, buf, offset); \ } \ static ssize_t \ -store_regs_sensor_##offset (struct device *dev, const char *buf, size_t count) \ +store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ return store_sensor_reg(dev, buf, count, offset); \ } \ -- cgit v0.10.2 From e404e274f62665f3333d6a539d0d3701f678a598 Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:42:58 -0400 Subject: [PATCH] Driver Core: drivers/i2c/chips/w83781d.c - drivers/s390/block/dcssblk.c: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index 4954e46..c3926d2 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -309,18 +309,18 @@ store_in_reg(MAX, max); #define sysfs_in_offset(offset) \ static ssize_t \ -show_regs_in_##offset (struct device *dev, char *buf) \ +show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in(dev, buf, offset); \ } \ static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); #define sysfs_in_reg_offset(reg, offset) \ -static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_in_##reg (dev, buf, offset); \ } \ -static ssize_t store_regs_in_##reg##offset (struct device *dev, const char *buf, size_t count) \ +static ssize_t store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ return store_in_##reg (dev, buf, count, offset); \ } \ @@ -378,18 +378,18 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr) } #define sysfs_fan_offset(offset) \ -static ssize_t show_regs_fan_##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan(dev, buf, offset); \ } \ static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); #define sysfs_fan_min_offset(offset) \ -static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_min(dev, buf, offset); \ } \ -static ssize_t store_regs_fan_min##offset (struct device *dev, const char *buf, size_t count) \ +static ssize_t store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ return store_fan_min(dev, buf, count, offset); \ } \ @@ -452,18 +452,18 @@ store_temp_reg(HYST, max_hyst); #define sysfs_temp_offset(offset) \ static ssize_t \ -show_regs_temp_##offset (struct device *dev, char *buf) \ +show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp(dev, buf, offset); \ } \ static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); #define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_temp_##reg (dev, buf, offset); \ } \ -static ssize_t store_regs_temp_##reg##offset (struct device *dev, const char *buf, size_t count) \ +static ssize_t store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ return store_temp_##reg (dev, buf, count, offset); \ } \ @@ -486,7 +486,7 @@ device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ } while (0) static ssize_t -show_vid_reg(struct device *dev, char *buf) +show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); @@ -497,14 +497,14 @@ DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); #define device_create_file_vid(client) \ device_create_file(&client->dev, &dev_attr_cpu0_vid); static ssize_t -show_vrm_reg(struct device *dev, char *buf) +show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } static ssize_t -store_vrm_reg(struct device *dev, const char *buf, size_t count) +store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct w83781d_data *data = i2c_get_clientdata(client); @@ -521,7 +521,7 @@ DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); #define device_create_file_vrm(client) \ device_create_file(&client->dev, &dev_attr_vrm); static ssize_t -show_alarms_reg(struct device *dev, char *buf) +show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms)); @@ -531,13 +531,13 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); #define device_create_file_alarms(client) \ device_create_file(&client->dev, &dev_attr_alarms); -static ssize_t show_beep_mask (struct device *dev, char *buf) +static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%ld\n", (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type)); } -static ssize_t show_beep_enable (struct device *dev, char *buf) +static ssize_t show_beep_enable (struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%ld\n", @@ -583,11 +583,11 @@ store_beep_reg(struct device *dev, const char *buf, size_t count, } #define sysfs_beep(REG, reg) \ -static ssize_t show_regs_beep_##reg (struct device *dev, char *buf) \ +static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ { \ - return show_beep_##reg(dev, buf); \ + return show_beep_##reg(dev, attr, buf); \ } \ -static ssize_t store_regs_beep_##reg (struct device *dev, const char *buf, size_t count) \ +static ssize_t store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ return store_beep_reg(dev, buf, count, BEEP_##REG); \ } \ @@ -653,11 +653,11 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) } #define sysfs_fan_div(offset) \ -static ssize_t show_regs_fan_div_##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_fan_div_reg(dev, buf, offset); \ } \ -static ssize_t store_regs_fan_div_##offset (struct device *dev, const char *buf, size_t count) \ +static ssize_t store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ return store_fan_div_reg(dev, buf, count, offset - 1); \ } \ @@ -737,11 +737,11 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) } #define sysfs_pwm(offset) \ -static ssize_t show_regs_pwm_##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_pwm_reg(dev, buf, offset); \ } \ -static ssize_t store_regs_pwm_##offset (struct device *dev, \ +static ssize_t store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return store_pwm_reg(dev, buf, count, offset); \ @@ -750,11 +750,11 @@ static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ show_regs_pwm_##offset, store_regs_pwm_##offset); #define sysfs_pwmenable(offset) \ -static ssize_t show_regs_pwmenable_##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_pwmenable_reg(dev, buf, offset); \ } \ -static ssize_t store_regs_pwmenable_##offset (struct device *dev, \ +static ssize_t store_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ return store_pwmenable_reg(dev, buf, count, offset); \ @@ -832,11 +832,11 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) } #define sysfs_sensor(offset) \ -static ssize_t show_regs_sensor_##offset (struct device *dev, char *buf) \ +static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ { \ return show_sensor_reg(dev, buf, offset); \ } \ -static ssize_t store_regs_sensor_##offset (struct device *dev, const char *buf, size_t count) \ +static ssize_t store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ return store_sensor_reg(dev, buf, count, offset); \ } \ diff --git a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c index 59bbc58..74d4b58 100644 --- a/drivers/i2c/chips/w83l785ts.c +++ b/drivers/i2c/chips/w83l785ts.c @@ -118,13 +118,13 @@ struct w83l785ts_data { * Sysfs stuff */ -static ssize_t show_temp(struct device *dev, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) { struct w83l785ts_data *data = w83l785ts_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); } -static ssize_t show_temp_over(struct device *dev, char *buf) +static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) { struct w83l785ts_data *data = w83l785ts_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 9011627..a22e53b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -103,7 +103,7 @@ static struct class i2c_adapter_class = { .release = &i2c_adapter_class_dev_release, }; -static ssize_t show_adapter_name(struct device *dev, char *buf) +static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_adapter *adap = dev_to_i2c_adapter(dev); return sprintf(buf, "%s\n", adap->name); @@ -117,7 +117,7 @@ static void i2c_client_release(struct device *dev) complete(&client->released); } -static ssize_t show_client_name(struct device *dev, char *buf) +static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); return sprintf(buf, "%s\n", client->name); diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index a155b39..32abb6d 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -220,7 +220,7 @@ struct device nodemgr_dev_template_host = { #define fw_attr(class, class_type, field, type, format_string) \ -static ssize_t fw_show_##class##_##field (struct device *dev, char *buf)\ +static ssize_t fw_show_##class##_##field (struct device *dev, struct device_attribute *attr, char *buf)\ { \ class_type *class; \ class = container_of(dev, class_type, device); \ @@ -232,7 +232,7 @@ static struct device_attribute dev_attr_##class##_##field = { \ }; #define fw_attr_td(class, class_type, td_kv) \ -static ssize_t fw_show_##class##_##td_kv (struct device *dev, char *buf)\ +static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attribute *attr, char *buf)\ { \ int len; \ class_type *class = container_of(dev, class_type, device); \ @@ -265,7 +265,7 @@ static struct driver_attribute driver_attr_drv_##field = { \ }; -static ssize_t fw_show_ne_bus_options(struct device *dev, char *buf) +static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribute *attr, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); @@ -281,7 +281,7 @@ static ssize_t fw_show_ne_bus_options(struct device *dev, char *buf) static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL); -static ssize_t fw_show_ne_tlabels_free(struct device *dev, char *buf) +static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); return sprintf(buf, "%d\n", atomic_read(&ne->tpool->count.count) + 1); @@ -289,7 +289,7 @@ static ssize_t fw_show_ne_tlabels_free(struct device *dev, char *buf) static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL); -static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, char *buf) +static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, struct device_attribute *attr, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); return sprintf(buf, "%u\n", ne->tpool->allocations); @@ -297,7 +297,7 @@ static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, char *buf) static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL); -static ssize_t fw_show_ne_tlabels_mask(struct device *dev, char *buf) +static ssize_t fw_show_ne_tlabels_mask(struct device *dev, struct device_attribute *attr, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); #if (BITS_PER_LONG <= 32) @@ -309,7 +309,7 @@ static ssize_t fw_show_ne_tlabels_mask(struct device *dev, char *buf) static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL); -static ssize_t fw_set_ignore_driver(struct device *dev, const char *buf, size_t count) +static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct unit_directory *ud = container_of(dev, struct unit_directory, device); int state = simple_strtoul(buf, NULL, 10); @@ -324,7 +324,7 @@ static ssize_t fw_set_ignore_driver(struct device *dev, const char *buf, size_t return count; } -static ssize_t fw_get_ignore_driver(struct device *dev, char *buf) +static ssize_t fw_get_ignore_driver(struct device *dev, struct device_attribute *attr, char *buf) { struct unit_directory *ud = container_of(dev, struct unit_directory, device); diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 2bae300..32368f3 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -2648,7 +2648,7 @@ static const char *sbp2scsi_info (struct Scsi_Host *host) return "SCSI emulation for IEEE-1394 SBP-2 Devices"; } -static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev, char *buf) +static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev; struct scsi_id_instance_data *scsi_id; diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index f20c3f2..9b8ff39 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -453,13 +453,13 @@ static int gameport_thread(void *nothing) * Gameport port operations */ -static ssize_t gameport_show_description(struct device *dev, char *buf) +static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf) { struct gameport *gameport = to_gameport_port(dev); return sprintf(buf, "%s\n", gameport->name); } -static ssize_t gameport_rebind_driver(struct device *dev, const char *buf, size_t count) +static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct gameport *gameport = to_gameport_port(dev); struct device_driver *drv; diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 48fdf1e5..82fad9a 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -219,11 +219,11 @@ static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t #define ATKBD_DEFINE_ATTR(_name) \ static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \ -static ssize_t atkbd_do_show_##_name(struct device *d, char *b) \ +static ssize_t atkbd_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \ { \ return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ } \ -static ssize_t atkbd_do_set_##_name(struct device *d, const char *b, size_t s) \ +static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s) \ { \ return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \ } \ diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index bda5b06..79e17a0 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -91,11 +91,11 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun #define PSMOUSE_DEFINE_ATTR(_name) \ static ssize_t psmouse_attr_show_##_name(struct psmouse *, char *); \ static ssize_t psmouse_attr_set_##_name(struct psmouse *, const char *, size_t);\ -static ssize_t psmouse_do_show_##_name(struct device *d, char *b) \ +static ssize_t psmouse_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \ { \ return psmouse_attr_show_helper(d, b, psmouse_attr_show_##_name); \ } \ -static ssize_t psmouse_do_set_##_name(struct device *d, const char *b, size_t s)\ +static ssize_t psmouse_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s)\ { \ return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name); \ } \ diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 0beacb7..feab497 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -358,31 +358,31 @@ static int serio_thread(void *nothing) * Serio port operations */ -static ssize_t serio_show_description(struct device *dev, char *buf) +static ssize_t serio_show_description(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%s\n", serio->name); } -static ssize_t serio_show_id_type(struct device *dev, char *buf) +static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%02x\n", serio->id.type); } -static ssize_t serio_show_id_proto(struct device *dev, char *buf) +static ssize_t serio_show_id_proto(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%02x\n", serio->id.proto); } -static ssize_t serio_show_id_id(struct device *dev, char *buf) +static ssize_t serio_show_id_id(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%02x\n", serio->id.id); } -static ssize_t serio_show_id_extra(struct device *dev, char *buf) +static ssize_t serio_show_id_extra(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%02x\n", serio->id.extra); @@ -406,7 +406,7 @@ static struct attribute_group serio_id_attr_group = { .attrs = serio_device_id_attrs, }; -static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count) +static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct serio *serio = to_serio_port(dev); struct device_driver *drv; @@ -437,13 +437,13 @@ static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t c return retval; } -static ssize_t serio_show_bind_mode(struct device *dev, char *buf) +static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto"); } -static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t count) +static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct serio *serio = to_serio_port(dev); int retval; diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index d09308f..5ba190c 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -455,21 +455,22 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, * pass around to the attribute functions, so we don't really have * choice but implement a bunch of them... * + * FIXME, it does now... */ #define BUILD_SHOW_FUNC_INT(name, data) \ -static ssize_t show_##name(struct device *dev, char *buf) \ +static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return sprintf(buf, "%d\n", data); \ } #define BUILD_SHOW_FUNC_STR(name, data) \ -static ssize_t show_##name(struct device *dev, char *buf) \ +static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return sprintf(buf, "%s\n", data); \ } #define BUILD_SHOW_FUNC_FAN(name, data) \ -static ssize_t show_##name(struct device *dev, char *buf) \ +static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return sprintf(buf, "%d (%d rpm)\n", \ thermostat->last_speed[data], \ @@ -478,7 +479,7 @@ static ssize_t show_##name(struct device *dev, char *buf) \ } #define BUILD_STORE_FUNC_DEG(name, data) \ -static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ +static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \ { \ int val; \ int i; \ @@ -491,7 +492,7 @@ static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ } #define BUILD_STORE_FUNC_INT(name, data) \ -static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ +static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \ { \ u32 val; \ val = simple_strtoul(buf, NULL, 10); \ diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 82336a5..feb4e24 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -685,7 +685,7 @@ static void fetch_cpu_pumps_minmax(void) * the input twice... I accept patches :) */ #define BUILD_SHOW_FUNC_FIX(name, data) \ -static ssize_t show_##name(struct device *dev, char *buf) \ +static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ ssize_t r; \ down(&driver_lock); \ @@ -694,7 +694,7 @@ static ssize_t show_##name(struct device *dev, char *buf) \ return r; \ } #define BUILD_SHOW_FUNC_INT(name, data) \ -static ssize_t show_##name(struct device *dev, char *buf) \ +static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ return sprintf(buf, "%d", data); \ } diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index c153699..0bdb47f 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -107,13 +107,13 @@ print_temp( const char *s, int temp ) } static ssize_t -show_cpu_temperature( struct device *dev, char *buf ) +show_cpu_temperature( struct device *dev, struct device_attribute *attr, char *buf ) { return sprintf(buf, "%d.%d\n", x.temp>>8, (x.temp & 255)*10/256 ); } static ssize_t -show_case_temperature( struct device *dev, char *buf ) +show_case_temperature( struct device *dev, struct device_attribute *attr, char *buf ) { return sprintf(buf, "%d.%d\n", x.casetemp>>8, (x.casetemp & 255)*10/256 ); } diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c index ff9be67..09baa43 100644 --- a/drivers/mca/mca-bus.c +++ b/drivers/mca/mca-bus.c @@ -69,7 +69,7 @@ struct bus_type mca_bus_type = { }; EXPORT_SYMBOL (mca_bus_type); -static ssize_t mca_show_pos_id(struct device *dev, char *buf) +static ssize_t mca_show_pos_id(struct device *dev, struct device_attribute *attr, char *buf) { /* four digits, \n and trailing \0 */ struct mca_device *mca_dev = to_mca_device(dev); @@ -81,7 +81,7 @@ static ssize_t mca_show_pos_id(struct device *dev, char *buf) len = sprintf(buf, "none\n"); return len; } -static ssize_t mca_show_pos(struct device *dev, char *buf) +static ssize_t mca_show_pos(struct device *dev, struct device_attribute *attr, char *buf) { /* enough for 8 two byte hex chars plus space and new line */ int j, len=0; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 48ff314..a0078ae 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -2338,7 +2338,7 @@ slave_configure_exit: } ssize_t -mptscsih_store_queue_depth(struct device *dev, const char *buf, size_t count) +mptscsih_store_queue_depth(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int depth; struct scsi_device *sdev = to_scsi_device(dev); diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 9f51983..d73aec3 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -103,5 +103,5 @@ extern int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_F extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); -extern ssize_t mptscsih_store_queue_depth(struct device *dev, const char *buf, size_t count); +extern ssize_t mptscsih_store_queue_depth(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); extern void mptscsih_timer_expired(unsigned long data); diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index 29a56e9..5556cd3 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -22,7 +22,7 @@ #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) #define MMC_ATTR(name, fmt, args...) \ -static ssize_t mmc_##name##_show (struct device *dev, char *buf) \ +static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct mmc_card *card = dev_to_mmc_card(dev); \ return sprintf(buf, fmt, args); \ diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 41c7971..4c11048 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -38,7 +38,7 @@ /* A few routines that create sysfs entries for the hot plug controller */ -static ssize_t show_ctrl (struct device *dev, char *buf) +static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pci_dev; struct controller *ctrl; @@ -82,7 +82,7 @@ static ssize_t show_ctrl (struct device *dev, char *buf) } static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); -static ssize_t show_dev (struct device *dev, char *buf) +static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pci_dev; struct controller *ctrl; diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index 9a1ee13..c9445eb 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -38,7 +38,7 @@ /* A few routines that create sysfs entries for the hot plug controller */ -static ssize_t show_ctrl (struct device *dev, char *buf) +static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pci_dev; struct controller *ctrl; @@ -82,7 +82,7 @@ static ssize_t show_ctrl (struct device *dev, char *buf) } static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); -static ssize_t show_dev (struct device *dev, char *buf) +static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pci_dev; struct controller *ctrl; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index e8aad15..8b79609 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -29,7 +29,7 @@ static int sysfs_initialized; /* = 0 */ /* show configuration fields */ #define pci_config_attr(field, format_string) \ static ssize_t \ -field##_show(struct device *dev, char *buf) \ +field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pci_dev *pdev; \ \ @@ -44,7 +44,7 @@ pci_config_attr(subsystem_device, "0x%04x\n"); pci_config_attr(class, "0x%06x\n"); pci_config_attr(irq, "%u\n"); -static ssize_t local_cpus_show(struct device *dev, char *buf) +static ssize_t local_cpus_show(struct device *dev, struct device_attribute *attr, char *buf) { cpumask_t mask = pcibus_to_cpumask(to_pci_dev(dev)->bus); int len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask); @@ -54,7 +54,7 @@ static ssize_t local_cpus_show(struct device *dev, char *buf) /* show resources */ static ssize_t -resource_show(struct device * dev, char * buf) +resource_show(struct device * dev, struct device_attribute *attr, char * buf) { struct pci_dev * pci_dev = to_pci_dev(dev); char * str = buf; diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index c4ade28..569e55f 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -604,14 +604,14 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { /************************ per-device sysfs output ***************************/ #define pcmcia_device_attr(field, test, format) \ -static ssize_t field##_show (struct device *dev, char *buf) \ +static ssize_t field##_show (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ return p_dev->test ? sprintf (buf, format, p_dev->field) : -ENODEV; \ } #define pcmcia_device_stringattr(name, field) \ -static ssize_t name##_show (struct device *dev, char *buf) \ +static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ return p_dev->field ? sprintf (buf, "%s\n", p_dev->field) : -ENODEV; \ diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index 97eeecf..3252662 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c @@ -140,7 +140,7 @@ static void pnp_release_card(struct device *dmdev) } -static ssize_t pnp_show_card_name(struct device *dmdev, char *buf) +static ssize_t pnp_show_card_name(struct device *dmdev, struct device_attribute *attr, char *buf) { char *str = buf; struct pnp_card *card = to_pnp_card(dmdev); @@ -150,7 +150,7 @@ static ssize_t pnp_show_card_name(struct device *dmdev, char *buf) static DEVICE_ATTR(name,S_IRUGO,pnp_show_card_name,NULL); -static ssize_t pnp_show_card_ids(struct device *dmdev, char *buf) +static ssize_t pnp_show_card_ids(struct device *dmdev, struct device_attribute *attr, char *buf) { char *str = buf; struct pnp_card *card = to_pnp_card(dmdev); diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 53fac8b..a2d8ce7 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -205,7 +205,7 @@ static void pnp_print_option(pnp_info_buffer_t *buffer, char *space, } -static ssize_t pnp_show_options(struct device *dmdev, char *buf) +static ssize_t pnp_show_options(struct device *dmdev, struct device_attribute *attr, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); struct pnp_option * independent = dev->independent; @@ -236,7 +236,7 @@ static ssize_t pnp_show_options(struct device *dmdev, char *buf) static DEVICE_ATTR(options,S_IRUGO,pnp_show_options,NULL); -static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) +static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_attribute *attr, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); int i, ret; @@ -308,7 +308,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) extern struct semaphore pnp_res_mutex; static ssize_t -pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count) +pnp_set_current_resources(struct device * dmdev, struct device_attribute *attr, const char * ubuf, size_t count) { struct pnp_dev *dev = to_pnp_dev(dmdev); char *buf = (void *)ubuf; @@ -444,7 +444,7 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count static DEVICE_ATTR(resources,S_IRUGO | S_IWUSR, pnp_show_current_resources,pnp_set_current_resources); -static ssize_t pnp_show_current_ids(struct device *dmdev, char *buf) +static ssize_t pnp_show_current_ids(struct device *dmdev, struct device_attribute *attr, char *buf) { char *str = buf; struct pnp_dev *dev = to_pnp_dev(dmdev); diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 1aedc48..d948566 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -615,7 +615,7 @@ dasd_device_from_cdev(struct ccw_device *cdev) * readonly controls the readonly status of a dasd */ static ssize_t -dasd_ro_show(struct device *dev, char *buf) +dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dasd_devmap *devmap; int ro_flag; @@ -629,7 +629,7 @@ dasd_ro_show(struct device *dev, char *buf) } static ssize_t -dasd_ro_store(struct device *dev, const char *buf, size_t count) +dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct dasd_devmap *devmap; int ro_flag; @@ -656,7 +656,7 @@ static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store); * to talk to the device */ static ssize_t -dasd_use_diag_show(struct device *dev, char *buf) +dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dasd_devmap *devmap; int use_diag; @@ -670,7 +670,7 @@ dasd_use_diag_show(struct device *dev, char *buf) } static ssize_t -dasd_use_diag_store(struct device *dev, const char *buf, size_t count) +dasd_use_diag_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct dasd_devmap *devmap; ssize_t rc; @@ -698,7 +698,7 @@ static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store); static ssize_t -dasd_discipline_show(struct device *dev, char *buf) +dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dasd_devmap *devmap; char *dname; diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index a66b17b6..16ab8d3 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -45,16 +45,16 @@ static struct block_device_operations dcssblk_devops = { .release = dcssblk_release, }; -static ssize_t dcssblk_add_store(struct device * dev, const char * buf, +static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count); -static ssize_t dcssblk_remove_store(struct device * dev, const char * buf, +static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count); -static ssize_t dcssblk_save_store(struct device * dev, const char * buf, +static ssize_t dcssblk_save_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count); -static ssize_t dcssblk_save_show(struct device *dev, char *buf); -static ssize_t dcssblk_shared_store(struct device * dev, const char * buf, +static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count); -static ssize_t dcssblk_shared_show(struct device *dev, char *buf); +static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf); static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store); static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store); @@ -195,7 +195,7 @@ dcssblk_segment_warn(int rc, char* seg_name) * operation (show + store) */ static ssize_t -dcssblk_shared_show(struct device *dev, char *buf) +dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dcssblk_dev_info *dev_info; @@ -204,7 +204,7 @@ dcssblk_shared_show(struct device *dev, char *buf) } static ssize_t -dcssblk_shared_store(struct device *dev, const char *inbuf, size_t count) +dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) { struct dcssblk_dev_info *dev_info; int rc; @@ -288,7 +288,7 @@ out: * (show + store) */ static ssize_t -dcssblk_save_show(struct device *dev, char *buf) +dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dcssblk_dev_info *dev_info; @@ -297,7 +297,7 @@ dcssblk_save_show(struct device *dev, char *buf) } static ssize_t -dcssblk_save_store(struct device *dev, const char *inbuf, size_t count) +dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) { struct dcssblk_dev_info *dev_info; @@ -343,7 +343,7 @@ dcssblk_save_store(struct device *dev, const char *inbuf, size_t count) * device attribute for adding devices */ static ssize_t -dcssblk_add_store(struct device *dev, const char *buf, size_t count) +dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int rc, i; struct dcssblk_dev_info *dev_info; @@ -517,7 +517,7 @@ out_nobuf: * device attribute for removing devices */ static ssize_t -dcssblk_remove_store(struct device *dev, const char *buf, size_t count) +dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct dcssblk_dev_info *dev_info; int rc, i; -- cgit v0.10.2 From 3fd3c0a5f53a0f9d8987b90acbd84f7dd8ef606e Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:43:27 -0400 Subject: [PATCH] Driver Core: drivers/char/raw3270.c - drivers/net/netiucv.c: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 8e16a97..d5eefea 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -1084,7 +1084,7 @@ raw3270_probe (struct ccw_device *cdev) * Additional attributes for a 3270 device */ static ssize_t -raw3270_model_show(struct device *dev, char *buf) +raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%i\n", ((struct raw3270 *) dev->driver_data)->model); @@ -1092,7 +1092,7 @@ raw3270_model_show(struct device *dev, char *buf) static DEVICE_ATTR(model, 0444, raw3270_model_show, 0); static ssize_t -raw3270_rows_show(struct device *dev, char *buf) +raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%i\n", ((struct raw3270 *) dev->driver_data)->rows); @@ -1100,7 +1100,7 @@ raw3270_rows_show(struct device *dev, char *buf) static DEVICE_ATTR(rows, 0444, raw3270_rows_show, 0); static ssize_t -raw3270_columns_show(struct device *dev, char *buf) +raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%i\n", ((struct raw3270 *) dev->driver_data)->cols); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index e51046a..b4df4a5 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -107,7 +107,7 @@ busid_to_int(char *bus_id) * replaced by a link to the cdev tree. */ static ssize_t -tape_medium_state_show(struct device *dev, char *buf) +tape_medium_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tape_device *tdev; @@ -119,7 +119,7 @@ static DEVICE_ATTR(medium_state, 0444, tape_medium_state_show, NULL); static ssize_t -tape_first_minor_show(struct device *dev, char *buf) +tape_first_minor_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tape_device *tdev; @@ -131,7 +131,7 @@ static DEVICE_ATTR(first_minor, 0444, tape_first_minor_show, NULL); static ssize_t -tape_state_show(struct device *dev, char *buf) +tape_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tape_device *tdev; @@ -144,7 +144,7 @@ static DEVICE_ATTR(state, 0444, tape_state_show, NULL); static ssize_t -tape_operation_show(struct device *dev, char *buf) +tape_operation_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tape_device *tdev; ssize_t rc; @@ -171,7 +171,7 @@ static DEVICE_ATTR(operation, 0444, tape_operation_show, NULL); static ssize_t -tape_blocksize_show(struct device *dev, char *buf) +tape_blocksize_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tape_device *tdev; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 724ad87..f771732 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -548,7 +548,7 @@ vmlogrdr_read (struct file *filp, char *data, size_t count, loff_t * ppos) } static ssize_t -vmlogrdr_autopurge_store(struct device * dev, const char * buf, size_t count) { +vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret = count; @@ -567,7 +567,7 @@ vmlogrdr_autopurge_store(struct device * dev, const char * buf, size_t count) { static ssize_t -vmlogrdr_autopurge_show(struct device *dev, char *buf) { +vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vmlogrdr_priv_t *priv = dev->driver_data; return sprintf(buf, "%u\n", priv->autopurge); } @@ -578,7 +578,7 @@ static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show, static ssize_t -vmlogrdr_purge_store(struct device * dev, const char * buf, size_t count) { +vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { char cp_command[80]; char cp_response[80]; @@ -619,7 +619,7 @@ static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store); static ssize_t -vmlogrdr_autorecording_store(struct device *dev, const char *buf, +vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret = count; @@ -639,7 +639,7 @@ vmlogrdr_autorecording_store(struct device *dev, const char *buf, static ssize_t -vmlogrdr_autorecording_show(struct device *dev, char *buf) { +vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vmlogrdr_priv_t *priv = dev->driver_data; return sprintf(buf, "%u\n", priv->autorecording); } @@ -650,7 +650,7 @@ static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show, static ssize_t -vmlogrdr_recording_store(struct device * dev, const char * buf, size_t count) { +vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret; diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 21a75ee..306525a 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -77,7 +77,7 @@ __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) * longer needed or accidentially created. Saves memory :) */ static ssize_t -ccwgroup_ungroup_store(struct device *dev, const char *buf, size_t count) +ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccwgroup_device *gdev; @@ -310,7 +310,7 @@ ccwgroup_set_offline(struct ccwgroup_device *gdev) } static ssize_t -ccwgroup_online_store (struct device *dev, const char *buf, size_t count) +ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccwgroup_device *gdev; struct ccwgroup_driver *gdrv; @@ -338,7 +338,7 @@ ccwgroup_online_store (struct device *dev, const char *buf, size_t count) } static ssize_t -ccwgroup_online_show (struct device *dev, char *buf) +ccwgroup_online_show (struct device *dev, struct device_attribute *attr, char *buf) { int online; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index b35fe12..b86f94e 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -852,7 +852,7 @@ out: * Files for the channel path entries. */ static ssize_t -chp_status_show(struct device *dev, char *buf) +chp_status_show(struct device *dev, struct device_attribute *attr, char *buf) { struct channel_path *chp = container_of(dev, struct channel_path, dev); @@ -863,7 +863,7 @@ chp_status_show(struct device *dev, char *buf) } static ssize_t -chp_status_write(struct device *dev, const char *buf, size_t count) +chp_status_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct channel_path *cp = container_of(dev, struct channel_path, dev); char cmd[10]; @@ -888,7 +888,7 @@ chp_status_write(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write); static ssize_t -chp_type_show(struct device *dev, char *buf) +chp_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct channel_path *chp = container_of(dev, struct channel_path, dev); diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 49def26..8cc4f1a 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -796,7 +796,7 @@ cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) } static ssize_t -cmb_show_avg_sample_interval(struct device *dev, char *buf) +cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev; long interval; @@ -813,7 +813,7 @@ cmb_show_avg_sample_interval(struct device *dev, char *buf) } static ssize_t -cmb_show_avg_utilization(struct device *dev, char *buf) +cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf) { struct cmbdata data; u64 utilization; @@ -842,12 +842,12 @@ cmb_show_avg_utilization(struct device *dev, char *buf) } #define cmf_attr(name) \ -static ssize_t show_ ## name (struct device * dev, char * buf) \ +static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \ { return cmb_show_attr((dev), buf, cmb_ ## name); } \ static DEVICE_ATTR(name, 0444, show_ ## name, NULL); #define cmf_attr_avg(name) \ -static ssize_t show_avg_ ## name (struct device * dev, char * buf) \ +static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \ { return cmb_show_attr((dev), buf, cmb_ ## name); } \ static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL); @@ -902,12 +902,12 @@ static struct attribute_group cmf_attr_group_ext = { .attrs = cmf_attributes_ext, }; -static ssize_t cmb_enable_show(struct device *dev, char *buf) +static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0); } -static ssize_t cmb_enable_store(struct device *dev, const char *buf, size_t c) +static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c) { struct ccw_device *cdev; int ret; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index df03255..809e110 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -204,7 +204,7 @@ module_exit(cleanup_ccw_bus_type); * TODO: Split chpids and pimpampom up? Where is "in use" in the tree? */ static ssize_t -chpids_show (struct device * dev, char * buf) +chpids_show (struct device * dev, struct device_attribute *attr, char * buf) { struct subchannel *sch = to_subchannel(dev); struct ssd_info *ssd = &sch->ssd_info; @@ -219,7 +219,7 @@ chpids_show (struct device * dev, char * buf) } static ssize_t -pimpampom_show (struct device * dev, char * buf) +pimpampom_show (struct device * dev, struct device_attribute *attr, char * buf) { struct subchannel *sch = to_subchannel(dev); struct pmcw *pmcw = &sch->schib.pmcw; @@ -229,7 +229,7 @@ pimpampom_show (struct device * dev, char * buf) } static ssize_t -devtype_show (struct device *dev, char *buf) +devtype_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); @@ -242,7 +242,7 @@ devtype_show (struct device *dev, char *buf) } static ssize_t -cutype_show (struct device *dev, char *buf) +cutype_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); @@ -252,7 +252,7 @@ cutype_show (struct device *dev, char *buf) } static ssize_t -online_show (struct device *dev, char *buf) +online_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); @@ -350,7 +350,7 @@ ccw_device_set_online(struct ccw_device *cdev) } static ssize_t -online_store (struct device *dev, const char *buf, size_t count) +online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccw_device *cdev = to_ccwdev(dev); int i, force, ret; @@ -422,7 +422,7 @@ online_store (struct device *dev, const char *buf, size_t count) } static ssize_t -available_show (struct device *dev, char *buf) +available_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch; diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 06804d3..a99927d5 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -241,20 +241,20 @@ static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr); static void dumpit (char *buf, int len); #endif /* sysfs Functions */ -static ssize_t claw_hname_show(struct device *dev, char *buf); -static ssize_t claw_hname_write(struct device *dev, +static ssize_t claw_hname_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t claw_hname_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); -static ssize_t claw_adname_show(struct device *dev, char *buf); -static ssize_t claw_adname_write(struct device *dev, +static ssize_t claw_adname_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t claw_adname_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); -static ssize_t claw_apname_show(struct device *dev, char *buf); -static ssize_t claw_apname_write(struct device *dev, +static ssize_t claw_apname_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t claw_apname_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); -static ssize_t claw_wbuff_show(struct device *dev, char *buf); -static ssize_t claw_wbuff_write(struct device *dev, +static ssize_t claw_wbuff_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t claw_wbuff_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); -static ssize_t claw_rbuff_show(struct device *dev, char *buf); -static ssize_t claw_rbuff_write(struct device *dev, +static ssize_t claw_rbuff_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t claw_rbuff_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); static int claw_add_files(struct device *dev); static void claw_remove_files(struct device *dev); @@ -4149,7 +4149,7 @@ claw_remove_device(struct ccwgroup_device *cgdev) * sysfs attributes */ static ssize_t -claw_hname_show(struct device *dev, char *buf) +claw_hname_show(struct device *dev, struct device_attribute *attr, char *buf) { struct claw_privbk *priv; struct claw_env * p_env; @@ -4162,7 +4162,7 @@ claw_hname_show(struct device *dev, char *buf) } static ssize_t -claw_hname_write(struct device *dev, const char *buf, size_t count) +claw_hname_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct claw_privbk *priv; struct claw_env * p_env; @@ -4186,7 +4186,7 @@ claw_hname_write(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(host_name, 0644, claw_hname_show, claw_hname_write); static ssize_t -claw_adname_show(struct device *dev, char *buf) +claw_adname_show(struct device *dev, struct device_attribute *attr, char *buf) { struct claw_privbk *priv; struct claw_env * p_env; @@ -4199,7 +4199,7 @@ claw_adname_show(struct device *dev, char *buf) } static ssize_t -claw_adname_write(struct device *dev, const char *buf, size_t count) +claw_adname_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct claw_privbk *priv; struct claw_env * p_env; @@ -4223,7 +4223,7 @@ claw_adname_write(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(adapter_name, 0644, claw_adname_show, claw_adname_write); static ssize_t -claw_apname_show(struct device *dev, char *buf) +claw_apname_show(struct device *dev, struct device_attribute *attr, char *buf) { struct claw_privbk *priv; struct claw_env * p_env; @@ -4237,7 +4237,7 @@ claw_apname_show(struct device *dev, char *buf) } static ssize_t -claw_apname_write(struct device *dev, const char *buf, size_t count) +claw_apname_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct claw_privbk *priv; struct claw_env * p_env; @@ -4271,7 +4271,7 @@ claw_apname_write(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(api_type, 0644, claw_apname_show, claw_apname_write); static ssize_t -claw_wbuff_show(struct device *dev, char *buf) +claw_wbuff_show(struct device *dev, struct device_attribute *attr, char *buf) { struct claw_privbk *priv; struct claw_env * p_env; @@ -4284,7 +4284,7 @@ claw_wbuff_show(struct device *dev, char *buf) } static ssize_t -claw_wbuff_write(struct device *dev, const char *buf, size_t count) +claw_wbuff_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct claw_privbk *priv; struct claw_env * p_env; @@ -4312,7 +4312,7 @@ claw_wbuff_write(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(write_buffer, 0644, claw_wbuff_show, claw_wbuff_write); static ssize_t -claw_rbuff_show(struct device *dev, char *buf) +claw_rbuff_show(struct device *dev, struct device_attribute *attr, char *buf) { struct claw_privbk *priv; struct claw_env * p_env; @@ -4325,7 +4325,7 @@ claw_rbuff_show(struct device *dev, char *buf) } static ssize_t -claw_rbuff_write(struct device *dev, const char *buf, size_t count) +claw_rbuff_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct claw_privbk *priv; struct claw_env *p_env; diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index ff3e95e..96ca863 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c @@ -2469,7 +2469,7 @@ ctc_stats(struct net_device * dev) */ static ssize_t -buffer_show(struct device *dev, char *buf) +buffer_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ctc_priv *priv; @@ -2481,7 +2481,7 @@ buffer_show(struct device *dev, char *buf) } static ssize_t -buffer_write(struct device *dev, const char *buf, size_t count) +buffer_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ctc_priv *priv; struct net_device *ndev; @@ -2530,13 +2530,13 @@ einval: } static ssize_t -loglevel_show(struct device *dev, char *buf) +loglevel_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", loglevel); } static ssize_t -loglevel_write(struct device *dev, const char *buf, size_t count) +loglevel_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ll1; @@ -2589,7 +2589,7 @@ ctc_print_statistics(struct ctc_priv *priv) } static ssize_t -stats_show(struct device *dev, char *buf) +stats_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ctc_priv *priv = dev->driver_data; if (!priv) @@ -2599,7 +2599,7 @@ stats_show(struct device *dev, char *buf) } static ssize_t -stats_write(struct device *dev, const char *buf, size_t count) +stats_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ctc_priv *priv = dev->driver_data; if (!priv) @@ -2654,7 +2654,7 @@ ctc_free_netdevice(struct net_device * dev, int free_dev) } static ssize_t -ctc_proto_show(struct device *dev, char *buf) +ctc_proto_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ctc_priv *priv; @@ -2666,7 +2666,7 @@ ctc_proto_show(struct device *dev, char *buf) } static ssize_t -ctc_proto_store(struct device *dev, const char *buf, size_t count) +ctc_proto_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ctc_priv *priv; int value; @@ -2687,7 +2687,7 @@ ctc_proto_store(struct device *dev, const char *buf, size_t count) static ssize_t -ctc_type_show(struct device *dev, char *buf) +ctc_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ccwgroup_device *cgdev; diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index cccfed2..ab08624 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1984,7 +1984,7 @@ lcs_open_device(struct net_device *dev) * show function for portno called by cat or similar things */ static ssize_t -lcs_portno_show (struct device *dev, char *buf) +lcs_portno_show (struct device *dev, struct device_attribute *attr, char *buf) { struct lcs_card *card; @@ -2000,7 +2000,7 @@ lcs_portno_show (struct device *dev, char *buf) * store the value which is piped to file portno */ static ssize_t -lcs_portno_store (struct device *dev, const char *buf, size_t count) +lcs_portno_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lcs_card *card; int value; @@ -2021,7 +2021,7 @@ lcs_portno_store (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(portno, 0644, lcs_portno_show, lcs_portno_store); static ssize_t -lcs_type_show(struct device *dev, char *buf) +lcs_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ccwgroup_device *cgdev; @@ -2035,7 +2035,7 @@ lcs_type_show(struct device *dev, char *buf) static DEVICE_ATTR(type, 0444, lcs_type_show, NULL); static ssize_t -lcs_timeout_show(struct device *dev, char *buf) +lcs_timeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lcs_card *card; @@ -2045,7 +2045,7 @@ lcs_timeout_show(struct device *dev, char *buf) } static ssize_t -lcs_timeout_store (struct device *dev, const char *buf, size_t count) +lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lcs_card *card; int value; diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 16e8e69..3fd4fb7 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1356,7 +1356,7 @@ netiucv_change_mtu (struct net_device * dev, int new_mtu) *****************************************************************************/ static ssize_t -user_show (struct device *dev, char *buf) +user_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1365,7 +1365,7 @@ user_show (struct device *dev, char *buf) } static ssize_t -user_write (struct device *dev, const char *buf, size_t count) +user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; struct net_device *ndev = priv->conn->netdev; @@ -1422,7 +1422,7 @@ user_write (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(user, 0644, user_show, user_write); static ssize_t -buffer_show (struct device *dev, char *buf) +buffer_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1431,7 +1431,7 @@ buffer_show (struct device *dev, char *buf) } static ssize_t -buffer_write (struct device *dev, const char *buf, size_t count) +buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; struct net_device *ndev = priv->conn->netdev; @@ -1486,7 +1486,7 @@ buffer_write (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); static ssize_t -dev_fsm_show (struct device *dev, char *buf) +dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1497,7 +1497,7 @@ dev_fsm_show (struct device *dev, char *buf) static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); static ssize_t -conn_fsm_show (struct device *dev, char *buf) +conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1508,7 +1508,7 @@ conn_fsm_show (struct device *dev, char *buf) static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); static ssize_t -maxmulti_show (struct device *dev, char *buf) +maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1517,7 +1517,7 @@ maxmulti_show (struct device *dev, char *buf) } static ssize_t -maxmulti_write (struct device *dev, const char *buf, size_t count) +maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1529,7 +1529,7 @@ maxmulti_write (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); static ssize_t -maxcq_show (struct device *dev, char *buf) +maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1538,7 +1538,7 @@ maxcq_show (struct device *dev, char *buf) } static ssize_t -maxcq_write (struct device *dev, const char *buf, size_t count) +maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1550,7 +1550,7 @@ maxcq_write (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); static ssize_t -sdoio_show (struct device *dev, char *buf) +sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1559,7 +1559,7 @@ sdoio_show (struct device *dev, char *buf) } static ssize_t -sdoio_write (struct device *dev, const char *buf, size_t count) +sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1571,7 +1571,7 @@ sdoio_write (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); static ssize_t -mdoio_show (struct device *dev, char *buf) +mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1580,7 +1580,7 @@ mdoio_show (struct device *dev, char *buf) } static ssize_t -mdoio_write (struct device *dev, const char *buf, size_t count) +mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1592,7 +1592,7 @@ mdoio_write (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); static ssize_t -txlen_show (struct device *dev, char *buf) +txlen_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1601,7 +1601,7 @@ txlen_show (struct device *dev, char *buf) } static ssize_t -txlen_write (struct device *dev, const char *buf, size_t count) +txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1613,7 +1613,7 @@ txlen_write (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); static ssize_t -txtime_show (struct device *dev, char *buf) +txtime_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1622,7 +1622,7 @@ txtime_show (struct device *dev, char *buf) } static ssize_t -txtime_write (struct device *dev, const char *buf, size_t count) +txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1634,7 +1634,7 @@ txtime_write (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); static ssize_t -txpend_show (struct device *dev, char *buf) +txpend_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1643,7 +1643,7 @@ txpend_show (struct device *dev, char *buf) } static ssize_t -txpend_write (struct device *dev, const char *buf, size_t count) +txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1655,7 +1655,7 @@ txpend_write (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); static ssize_t -txmpnd_show (struct device *dev, char *buf) +txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1664,7 +1664,7 @@ txmpnd_show (struct device *dev, char *buf) } static ssize_t -txmpnd_write (struct device *dev, const char *buf, size_t count) +txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; -- cgit v0.10.2 From 10523b3b82456e416cbaffcc24ea2246980aa746 Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:43:37 -0400 Subject: [PATCH] Driver Core: drivers/s390/net/qeth_sys.c - drivers/usb/gadget/pxa2xx_udc.c: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index 2403483..98bedb0 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -30,7 +30,7 @@ const char *VERSION_QETH_SYS_C = "$Revision: 1.51 $"; //low/high watermark static ssize_t -qeth_dev_state_show(struct device *dev, char *buf) +qeth_dev_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; if (!card) @@ -58,7 +58,7 @@ qeth_dev_state_show(struct device *dev, char *buf) static DEVICE_ATTR(state, 0444, qeth_dev_state_show, NULL); static ssize_t -qeth_dev_chpid_show(struct device *dev, char *buf) +qeth_dev_chpid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; if (!card) @@ -70,7 +70,7 @@ qeth_dev_chpid_show(struct device *dev, char *buf) static DEVICE_ATTR(chpid, 0444, qeth_dev_chpid_show, NULL); static ssize_t -qeth_dev_if_name_show(struct device *dev, char *buf) +qeth_dev_if_name_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; if (!card) @@ -81,7 +81,7 @@ qeth_dev_if_name_show(struct device *dev, char *buf) static DEVICE_ATTR(if_name, 0444, qeth_dev_if_name_show, NULL); static ssize_t -qeth_dev_card_type_show(struct device *dev, char *buf) +qeth_dev_card_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; if (!card) @@ -93,7 +93,7 @@ qeth_dev_card_type_show(struct device *dev, char *buf) static DEVICE_ATTR(card_type, 0444, qeth_dev_card_type_show, NULL); static ssize_t -qeth_dev_portno_show(struct device *dev, char *buf) +qeth_dev_portno_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; if (!card) @@ -103,7 +103,7 @@ qeth_dev_portno_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_portno_store(struct device *dev, const char *buf, size_t count) +qeth_dev_portno_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -129,7 +129,7 @@ qeth_dev_portno_store(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(portno, 0644, qeth_dev_portno_show, qeth_dev_portno_store); static ssize_t -qeth_dev_portname_show(struct device *dev, char *buf) +qeth_dev_portname_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; char portname[9] = {0, }; @@ -146,7 +146,7 @@ qeth_dev_portname_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_portname_store(struct device *dev, const char *buf, size_t count) +qeth_dev_portname_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -177,7 +177,7 @@ static DEVICE_ATTR(portname, 0644, qeth_dev_portname_show, qeth_dev_portname_store); static ssize_t -qeth_dev_checksum_show(struct device *dev, char *buf) +qeth_dev_checksum_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -188,7 +188,7 @@ qeth_dev_checksum_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_checksum_store(struct device *dev, const char *buf, size_t count) +qeth_dev_checksum_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -218,7 +218,7 @@ static DEVICE_ATTR(checksumming, 0644, qeth_dev_checksum_show, qeth_dev_checksum_store); static ssize_t -qeth_dev_prioqing_show(struct device *dev, char *buf) +qeth_dev_prioqing_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -237,7 +237,7 @@ qeth_dev_prioqing_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_prioqing_store(struct device *dev, const char *buf, size_t count) +qeth_dev_prioqing_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -290,7 +290,7 @@ static DEVICE_ATTR(priority_queueing, 0644, qeth_dev_prioqing_show, qeth_dev_prioqing_store); static ssize_t -qeth_dev_bufcnt_show(struct device *dev, char *buf) +qeth_dev_bufcnt_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -301,7 +301,7 @@ qeth_dev_bufcnt_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_bufcnt_store(struct device *dev, const char *buf, size_t count) +qeth_dev_bufcnt_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -360,7 +360,7 @@ qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route, } static ssize_t -qeth_dev_route4_show(struct device *dev, char *buf) +qeth_dev_route4_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -410,7 +410,7 @@ qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route, } static ssize_t -qeth_dev_route4_store(struct device *dev, const char *buf, size_t count) +qeth_dev_route4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -425,7 +425,7 @@ static DEVICE_ATTR(route4, 0644, qeth_dev_route4_show, qeth_dev_route4_store); #ifdef CONFIG_QETH_IPV6 static ssize_t -qeth_dev_route6_show(struct device *dev, char *buf) +qeth_dev_route6_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -439,7 +439,7 @@ qeth_dev_route6_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_route6_store(struct device *dev, const char *buf, size_t count) +qeth_dev_route6_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -461,7 +461,7 @@ static DEVICE_ATTR(route6, 0644, qeth_dev_route6_show, qeth_dev_route6_store); #endif static ssize_t -qeth_dev_add_hhlen_show(struct device *dev, char *buf) +qeth_dev_add_hhlen_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -472,7 +472,7 @@ qeth_dev_add_hhlen_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_add_hhlen_store(struct device *dev, const char *buf, size_t count) +qeth_dev_add_hhlen_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -499,7 +499,7 @@ static DEVICE_ATTR(add_hhlen, 0644, qeth_dev_add_hhlen_show, qeth_dev_add_hhlen_store); static ssize_t -qeth_dev_fake_ll_show(struct device *dev, char *buf) +qeth_dev_fake_ll_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -510,7 +510,7 @@ qeth_dev_fake_ll_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_fake_ll_store(struct device *dev, const char *buf, size_t count) +qeth_dev_fake_ll_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -536,7 +536,7 @@ static DEVICE_ATTR(fake_ll, 0644, qeth_dev_fake_ll_show, qeth_dev_fake_ll_store); static ssize_t -qeth_dev_fake_broadcast_show(struct device *dev, char *buf) +qeth_dev_fake_broadcast_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -547,7 +547,7 @@ qeth_dev_fake_broadcast_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_fake_broadcast_store(struct device *dev, const char *buf, size_t count) +qeth_dev_fake_broadcast_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -574,7 +574,7 @@ static DEVICE_ATTR(fake_broadcast, 0644, qeth_dev_fake_broadcast_show, qeth_dev_fake_broadcast_store); static ssize_t -qeth_dev_recover_store(struct device *dev, const char *buf, size_t count) +qeth_dev_recover_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -596,7 +596,7 @@ qeth_dev_recover_store(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store); static ssize_t -qeth_dev_broadcast_mode_show(struct device *dev, char *buf) +qeth_dev_broadcast_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -613,7 +613,7 @@ qeth_dev_broadcast_mode_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_broadcast_mode_store(struct device *dev, const char *buf, size_t count) +qeth_dev_broadcast_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -651,7 +651,7 @@ static DEVICE_ATTR(broadcast_mode, 0644, qeth_dev_broadcast_mode_show, qeth_dev_broadcast_mode_store); static ssize_t -qeth_dev_canonical_macaddr_show(struct device *dev, char *buf) +qeth_dev_canonical_macaddr_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -667,7 +667,7 @@ qeth_dev_canonical_macaddr_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_canonical_macaddr_store(struct device *dev, const char *buf, +qeth_dev_canonical_macaddr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -703,7 +703,7 @@ static DEVICE_ATTR(canonical_macaddr, 0644, qeth_dev_canonical_macaddr_show, qeth_dev_canonical_macaddr_store); static ssize_t -qeth_dev_layer2_show(struct device *dev, char *buf) +qeth_dev_layer2_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -714,7 +714,7 @@ qeth_dev_layer2_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_layer2_store(struct device *dev, const char *buf, size_t count) +qeth_dev_layer2_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -742,7 +742,7 @@ static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show, qeth_dev_layer2_store); static ssize_t -qeth_dev_large_send_show(struct device *dev, char *buf) +qeth_dev_large_send_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -762,7 +762,7 @@ qeth_dev_large_send_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_large_send_store(struct device *dev, const char *buf, size_t count) +qeth_dev_large_send_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; enum qeth_large_send_types type; @@ -832,7 +832,7 @@ qeth_dev_blkt_store(struct qeth_card *card, const char *buf, size_t count, } static ssize_t -qeth_dev_blkt_total_show(struct device *dev, char *buf) +qeth_dev_blkt_total_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -841,7 +841,7 @@ qeth_dev_blkt_total_show(struct device *dev, char *buf) static ssize_t -qeth_dev_blkt_total_store(struct device *dev, const char *buf, size_t count) +qeth_dev_blkt_total_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -855,7 +855,7 @@ static DEVICE_ATTR(total, 0644, qeth_dev_blkt_total_show, qeth_dev_blkt_total_store); static ssize_t -qeth_dev_blkt_inter_show(struct device *dev, char *buf) +qeth_dev_blkt_inter_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -864,7 +864,7 @@ qeth_dev_blkt_inter_show(struct device *dev, char *buf) static ssize_t -qeth_dev_blkt_inter_store(struct device *dev, const char *buf, size_t count) +qeth_dev_blkt_inter_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -876,7 +876,7 @@ static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show, qeth_dev_blkt_inter_store); static ssize_t -qeth_dev_blkt_inter_jumbo_show(struct device *dev, char *buf) +qeth_dev_blkt_inter_jumbo_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -886,7 +886,7 @@ qeth_dev_blkt_inter_jumbo_show(struct device *dev, char *buf) static ssize_t -qeth_dev_blkt_inter_jumbo_store(struct device *dev, const char *buf, size_t count) +qeth_dev_blkt_inter_jumbo_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -956,7 +956,7 @@ qeth_check_layer2(struct qeth_card *card) static ssize_t -qeth_dev_ipato_enable_show(struct device *dev, char *buf) +qeth_dev_ipato_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -969,7 +969,7 @@ qeth_dev_ipato_enable_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_ipato_enable_store(struct device *dev, const char *buf, size_t count) +qeth_dev_ipato_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -1004,7 +1004,7 @@ static QETH_DEVICE_ATTR(ipato_enable, enable, 0644, qeth_dev_ipato_enable_store); static ssize_t -qeth_dev_ipato_invert4_show(struct device *dev, char *buf) +qeth_dev_ipato_invert4_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -1018,7 +1018,7 @@ qeth_dev_ipato_invert4_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_ipato_invert4_store(struct device *dev, const char *buf, size_t count) +qeth_dev_ipato_invert4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -1084,7 +1084,7 @@ qeth_dev_ipato_add_show(char *buf, struct qeth_card *card, } static ssize_t -qeth_dev_ipato_add4_show(struct device *dev, char *buf) +qeth_dev_ipato_add4_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -1153,7 +1153,7 @@ qeth_dev_ipato_add_store(const char *buf, size_t count, } static ssize_t -qeth_dev_ipato_add4_store(struct device *dev, const char *buf, size_t count) +qeth_dev_ipato_add4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1186,7 +1186,7 @@ qeth_dev_ipato_del_store(const char *buf, size_t count, } static ssize_t -qeth_dev_ipato_del4_store(struct device *dev, const char *buf, size_t count) +qeth_dev_ipato_del4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1201,7 +1201,7 @@ static QETH_DEVICE_ATTR(ipato_del4, del4, 0200, NULL, #ifdef CONFIG_QETH_IPV6 static ssize_t -qeth_dev_ipato_invert6_show(struct device *dev, char *buf) +qeth_dev_ipato_invert6_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -1215,7 +1215,7 @@ qeth_dev_ipato_invert6_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_ipato_invert6_store(struct device *dev, const char *buf, size_t count) +qeth_dev_ipato_invert6_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; char *tmp; @@ -1247,7 +1247,7 @@ static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644, static ssize_t -qeth_dev_ipato_add6_show(struct device *dev, char *buf) +qeth_dev_ipato_add6_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -1258,7 +1258,7 @@ qeth_dev_ipato_add6_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_ipato_add6_store(struct device *dev, const char *buf, size_t count) +qeth_dev_ipato_add6_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1273,7 +1273,7 @@ static QETH_DEVICE_ATTR(ipato_add6, add6, 0644, qeth_dev_ipato_add6_store); static ssize_t -qeth_dev_ipato_del6_store(struct device *dev, const char *buf, size_t count) +qeth_dev_ipato_del6_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1341,7 +1341,7 @@ qeth_dev_vipa_add_show(char *buf, struct qeth_card *card, } static ssize_t -qeth_dev_vipa_add4_show(struct device *dev, char *buf) +qeth_dev_vipa_add4_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -1381,7 +1381,7 @@ qeth_dev_vipa_add_store(const char *buf, size_t count, } static ssize_t -qeth_dev_vipa_add4_store(struct device *dev, const char *buf, size_t count) +qeth_dev_vipa_add4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1413,7 +1413,7 @@ qeth_dev_vipa_del_store(const char *buf, size_t count, } static ssize_t -qeth_dev_vipa_del4_store(struct device *dev, const char *buf, size_t count) +qeth_dev_vipa_del4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1428,7 +1428,7 @@ static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL, #ifdef CONFIG_QETH_IPV6 static ssize_t -qeth_dev_vipa_add6_show(struct device *dev, char *buf) +qeth_dev_vipa_add6_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -1439,7 +1439,7 @@ qeth_dev_vipa_add6_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_vipa_add6_store(struct device *dev, const char *buf, size_t count) +qeth_dev_vipa_add6_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1454,7 +1454,7 @@ static QETH_DEVICE_ATTR(vipa_add6, add6, 0644, qeth_dev_vipa_add6_store); static ssize_t -qeth_dev_vipa_del6_store(struct device *dev, const char *buf, size_t count) +qeth_dev_vipa_del6_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1522,7 +1522,7 @@ qeth_dev_rxip_add_show(char *buf, struct qeth_card *card, } static ssize_t -qeth_dev_rxip_add4_show(struct device *dev, char *buf) +qeth_dev_rxip_add4_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -1562,7 +1562,7 @@ qeth_dev_rxip_add_store(const char *buf, size_t count, } static ssize_t -qeth_dev_rxip_add4_store(struct device *dev, const char *buf, size_t count) +qeth_dev_rxip_add4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1594,7 +1594,7 @@ qeth_dev_rxip_del_store(const char *buf, size_t count, } static ssize_t -qeth_dev_rxip_del4_store(struct device *dev, const char *buf, size_t count) +qeth_dev_rxip_del4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1609,7 +1609,7 @@ static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL, #ifdef CONFIG_QETH_IPV6 static ssize_t -qeth_dev_rxip_add6_show(struct device *dev, char *buf) +qeth_dev_rxip_add6_show(struct device *dev, struct device_attribute *attr, char *buf) { struct qeth_card *card = dev->driver_data; @@ -1620,7 +1620,7 @@ qeth_dev_rxip_add6_show(struct device *dev, char *buf) } static ssize_t -qeth_dev_rxip_add6_store(struct device *dev, const char *buf, size_t count) +qeth_dev_rxip_add6_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; @@ -1635,7 +1635,7 @@ static QETH_DEVICE_ATTR(rxip_add6, add6, 0644, qeth_dev_rxip_add6_store); static ssize_t -qeth_dev_rxip_del6_store(struct device *dev, const char *buf, size_t count) +qeth_dev_rxip_del6_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev->driver_data; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 6965992..b61d309 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -924,7 +924,7 @@ struct fc_function_template zfcp_transport_functions = { * Generates attribute for a unit. */ #define ZFCP_DEFINE_SCSI_ATTR(_name, _format, _value) \ -static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \ +static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct scsi_device *sdev; \ diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c index 23e2dca..e7345a7 100644 --- a/drivers/s390/scsi/zfcp_sysfs_adapter.c +++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c @@ -50,7 +50,7 @@ static const char fc_topologies[5][25] = { * Generates attributes for an adapter. */ #define ZFCP_DEFINE_ADAPTER_ATTR(_name, _format, _value) \ -static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \ +static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct zfcp_adapter *adapter; \ @@ -90,7 +90,7 @@ ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask * Store function of the "port_add" attribute of an adapter. */ static ssize_t -zfcp_sysfs_port_add_store(struct device *dev, const char *buf, size_t count) +zfcp_sysfs_port_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { wwn_t wwpn; char *endp; @@ -135,7 +135,7 @@ static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store); * Store function of the "port_remove" attribute of an adapter. */ static ssize_t -zfcp_sysfs_port_remove_store(struct device *dev, const char *buf, size_t count) +zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct zfcp_adapter *adapter; struct zfcp_port *port; @@ -196,7 +196,7 @@ static DEVICE_ATTR(port_remove, S_IWUSR, NULL, zfcp_sysfs_port_remove_store); * started for the belonging adapter. */ static ssize_t -zfcp_sysfs_adapter_failed_store(struct device *dev, +zfcp_sysfs_adapter_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct zfcp_adapter *adapter; @@ -236,7 +236,7 @@ zfcp_sysfs_adapter_failed_store(struct device *dev, * "0" if adapter is working, otherwise "1". */ static ssize_t -zfcp_sysfs_adapter_failed_show(struct device *dev, char *buf) +zfcp_sysfs_adapter_failed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct zfcp_adapter *adapter; diff --git a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c index 6aafb2a..7a84c7d 100644 --- a/drivers/s390/scsi/zfcp_sysfs_port.c +++ b/drivers/s390/scsi/zfcp_sysfs_port.c @@ -53,7 +53,7 @@ zfcp_sysfs_port_release(struct device *dev) * Generates attributes for a port. */ #define ZFCP_DEFINE_PORT_ATTR(_name, _format, _value) \ -static ssize_t zfcp_sysfs_port_##_name##_show(struct device *dev, \ +static ssize_t zfcp_sysfs_port_##_name##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct zfcp_port *port; \ @@ -82,7 +82,7 @@ ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask * Store function of the "unit_add" attribute of a port. */ static ssize_t -zfcp_sysfs_unit_add_store(struct device *dev, const char *buf, size_t count) +zfcp_sysfs_unit_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { fcp_lun_t fcp_lun; char *endp; @@ -125,7 +125,7 @@ static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); * @count: number of bytes in buffer */ static ssize_t -zfcp_sysfs_unit_remove_store(struct device *dev, const char *buf, size_t count) +zfcp_sysfs_unit_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct zfcp_port *port; struct zfcp_unit *unit; @@ -186,7 +186,7 @@ static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); * started for the belonging port. */ static ssize_t -zfcp_sysfs_port_failed_store(struct device *dev, const char *buf, size_t count) +zfcp_sysfs_port_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct zfcp_port *port; unsigned int val; @@ -224,7 +224,7 @@ zfcp_sysfs_port_failed_store(struct device *dev, const char *buf, size_t count) * "0" if port is working, otherwise "1". */ static ssize_t -zfcp_sysfs_port_failed_show(struct device *dev, char *buf) +zfcp_sysfs_port_failed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct zfcp_port *port; diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c index 87c0b461..0556642 100644 --- a/drivers/s390/scsi/zfcp_sysfs_unit.c +++ b/drivers/s390/scsi/zfcp_sysfs_unit.c @@ -53,7 +53,7 @@ zfcp_sysfs_unit_release(struct device *dev) * Generates attribute for a unit. */ #define ZFCP_DEFINE_UNIT_ATTR(_name, _format, _value) \ -static ssize_t zfcp_sysfs_unit_##_name##_show(struct device *dev, \ +static ssize_t zfcp_sysfs_unit_##_name##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct zfcp_unit *unit; \ @@ -86,7 +86,7 @@ ZFCP_DEFINE_UNIT_ATTR(access_readonly, "%d\n", atomic_test_mask * started for the belonging unit. */ static ssize_t -zfcp_sysfs_unit_failed_store(struct device *dev, const char *buf, size_t count) +zfcp_sysfs_unit_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct zfcp_unit *unit; unsigned int val; @@ -123,7 +123,7 @@ zfcp_sysfs_unit_failed_store(struct device *dev, const char *buf, size_t count) * "0" if unit is working, otherwise "1". */ static ssize_t -zfcp_sysfs_unit_failed_show(struct device *dev, char *buf) +zfcp_sysfs_unit_failed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct zfcp_unit *unit; diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index d151af9..a7620fc 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -2125,7 +2125,7 @@ static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type) } static ssize_t -NCR_700_show_active_tags(struct device *dev, char *buf) +NCR_700_show_active_tags(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *SDp = to_scsi_device(dev); diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index 78b7e54..ce711f1 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -466,7 +466,7 @@ int eesoxscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_ return pos; } -static ssize_t eesoxscsi_show_term(struct device *dev, char *buf) +static ssize_t eesoxscsi_show_term(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); struct Scsi_Host *host = ecard_get_drvdata(ec); @@ -475,7 +475,7 @@ static ssize_t eesoxscsi_show_term(struct device *dev, char *buf) return sprintf(buf, "%d\n", info->control & EESOX_TERM_ENABLE ? 1 : 0); } -static ssize_t eesoxscsi_store_term(struct device *dev, const char *buf, size_t len) +static ssize_t eesoxscsi_store_term(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct expansion_card *ec = ECARD_DEV(dev); struct Scsi_Host *host = ecard_get_drvdata(ec); diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index 54f23be..abda216 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -269,7 +269,7 @@ int powertecscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, o return pos; } -static ssize_t powertecscsi_show_term(struct device *dev, char *buf) +static ssize_t powertecscsi_show_term(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); struct Scsi_Host *host = ecard_get_drvdata(ec); @@ -279,7 +279,7 @@ static ssize_t powertecscsi_show_term(struct device *dev, char *buf) } static ssize_t -powertecscsi_store_term(struct device *dev, const char *buf, size_t len) +powertecscsi_store_term(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct expansion_card *ec = ECARD_DEV(dev); struct Scsi_Host *host = ecard_get_drvdata(ec); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 17b106b..80d0226 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -2716,7 +2716,7 @@ static int ipr_change_queue_type(struct scsi_device *sdev, int tag_type) * Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_show_adapter_handle(struct device *dev, char *buf) +static ssize_t ipr_show_adapter_handle(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 057ed45..cbe4302 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -124,7 +124,7 @@ static irqreturn_t megaraid_isr(int, void *, struct pt_regs *); static void megaraid_mbox_dpc(unsigned long); static ssize_t megaraid_sysfs_show_app_hndl(struct class_device *, char *); -static ssize_t megaraid_sysfs_show_ldnum(struct device *, char *); +static ssize_t megaraid_sysfs_show_ldnum(struct device *, struct device_attribute *attr, char *); static int megaraid_cmm_register(adapter_t *); static int megaraid_cmm_unregister(adapter_t *); @@ -4145,7 +4145,7 @@ megaraid_sysfs_show_app_hndl(struct class_device *cdev, char *buf) * @param buf : buffer to send data to */ static ssize_t -megaraid_sysfs_show_ldnum(struct device *dev, char *buf) +megaraid_sysfs_show_ldnum(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(sdev->host); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 7134618..93b4110 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -230,7 +230,7 @@ void scsi_sysfs_unregister(void) */ #define sdev_show_function(field, format_string) \ static ssize_t \ -sdev_show_##field (struct device *dev, char *buf) \ +sdev_show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct scsi_device *sdev; \ sdev = to_scsi_device(dev); \ @@ -254,7 +254,7 @@ static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL); sdev_show_function(field, format_string) \ \ static ssize_t \ -sdev_store_##field (struct device *dev, const char *buf, size_t count) \ +sdev_store_##field (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ struct scsi_device *sdev; \ sdev = to_scsi_device(dev); \ @@ -274,7 +274,7 @@ static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##fie sdev_show_function(field, "%d\n") \ \ static ssize_t \ -sdev_store_##field (struct device *dev, const char *buf, size_t count) \ +sdev_store_##field (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ int ret; \ struct scsi_device *sdev; \ @@ -317,7 +317,7 @@ sdev_rd_attr (model, "%.16s\n"); sdev_rd_attr (rev, "%.4s\n"); static ssize_t -sdev_show_timeout (struct device *dev, char *buf) +sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev; sdev = to_scsi_device(dev); @@ -325,7 +325,7 @@ sdev_show_timeout (struct device *dev, char *buf) } static ssize_t -sdev_store_timeout (struct device *dev, const char *buf, size_t count) +sdev_store_timeout (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct scsi_device *sdev; int timeout; @@ -337,14 +337,14 @@ sdev_store_timeout (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout); static ssize_t -store_rescan_field (struct device *dev, const char *buf, size_t count) +store_rescan_field (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { scsi_rescan_device(dev); return count; } static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field); -static ssize_t sdev_store_delete(struct device *dev, const char *buf, +static ssize_t sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { scsi_remove_device(to_scsi_device(dev)); @@ -353,7 +353,7 @@ static ssize_t sdev_store_delete(struct device *dev, const char *buf, static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete); static ssize_t -store_state_field(struct device *dev, const char *buf, size_t count) +store_state_field(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int i; struct scsi_device *sdev = to_scsi_device(dev); @@ -376,7 +376,7 @@ store_state_field(struct device *dev, const char *buf, size_t count) } static ssize_t -show_state_field(struct device *dev, char *buf) +show_state_field(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); const char *name = scsi_device_state_name(sdev->sdev_state); @@ -390,7 +390,7 @@ show_state_field(struct device *dev, char *buf) static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_state_field, store_state_field); static ssize_t -show_queue_type_field(struct device *dev, char *buf) +show_queue_type_field(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); const char *name = "none"; @@ -406,7 +406,7 @@ show_queue_type_field(struct device *dev, char *buf) static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL); static ssize_t -show_iostat_counterbits(struct device *dev, char *buf) +show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8); } @@ -415,7 +415,7 @@ static DEVICE_ATTR(iocounterbits, S_IRUGO, show_iostat_counterbits, NULL); #define show_sdev_iostat(field) \ static ssize_t \ -show_iostat_##field(struct device *dev, char *buf) \ +show_iostat_##field(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct scsi_device *sdev = to_scsi_device(dev); \ unsigned long long count = atomic_read(&sdev->field); \ @@ -449,7 +449,7 @@ static struct device_attribute *scsi_sysfs_sdev_attrs[] = { NULL }; -static ssize_t sdev_store_queue_depth_rw(struct device *dev, const char *buf, +static ssize_t sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int depth, retval; @@ -475,7 +475,7 @@ static struct device_attribute sdev_attr_queue_depth_rw = __ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth, sdev_store_queue_depth_rw); -static ssize_t sdev_store_queue_type_rw(struct device *dev, const char *buf, +static ssize_t sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct scsi_device *sdev = to_scsi_device(dev); diff --git a/drivers/sh/superhyway/superhyway-sysfs.c b/drivers/sh/superhyway/superhyway-sysfs.c index 39ab6a1..dc119ce 100644 --- a/drivers/sh/superhyway/superhyway-sysfs.c +++ b/drivers/sh/superhyway/superhyway-sysfs.c @@ -15,7 +15,7 @@ #include #define superhyway_ro_attr(name, fmt, field) \ -static ssize_t name##_show(struct device *dev, char *buf) \ +static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct superhyway_device *s = to_superhyway_device(dev); \ return sprintf(buf, fmt, s->field); \ diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 4d0c9e6..c1b8e69 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -24,7 +24,7 @@ /* Active configuration fields */ #define usb_actconfig_show(field, multiplier, format_string) \ -static ssize_t show_##field (struct device *dev, char *buf) \ +static ssize_t show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ @@ -46,7 +46,7 @@ usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") usb_actconfig_attr (bmAttributes, 1, "%2x\n") usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") -static ssize_t show_configuration_string(struct device *dev, char *buf) +static ssize_t show_configuration_string(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; struct usb_host_config *actconfig; @@ -69,7 +69,7 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); usb_actconfig_show(bConfigurationValue, 1, "%u\n"); static ssize_t -set_bConfigurationValue (struct device *dev, const char *buf, size_t count) +set_bConfigurationValue (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_device *udev = udev = to_usb_device (dev); int config, value; @@ -87,7 +87,7 @@ static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, /* String fields */ #define usb_string_attr(name) \ -static ssize_t show_##name(struct device *dev, char *buf) \ +static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ int len; \ @@ -107,7 +107,7 @@ usb_string_attr(manufacturer); usb_string_attr(serial); static ssize_t -show_speed (struct device *dev, char *buf) +show_speed (struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; char *speed; @@ -133,7 +133,7 @@ show_speed (struct device *dev, char *buf) static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); static ssize_t -show_devnum (struct device *dev, char *buf) +show_devnum (struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; @@ -143,7 +143,7 @@ show_devnum (struct device *dev, char *buf) static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); static ssize_t -show_version (struct device *dev, char *buf) +show_version (struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; u16 bcdUSB; @@ -155,7 +155,7 @@ show_version (struct device *dev, char *buf) static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); static ssize_t -show_maxchild (struct device *dev, char *buf) +show_maxchild (struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; @@ -167,7 +167,7 @@ static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); /* Descriptor fields */ #define usb_descriptor_attr_le16(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ \ @@ -183,7 +183,7 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n") #define usb_descriptor_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ \ @@ -254,7 +254,7 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) /* Interface fields */ #define usb_intf_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, char *buf) \ +show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_interface *intf = to_usb_interface (dev); \ \ @@ -269,7 +269,7 @@ usb_intf_attr (bInterfaceClass, "%02x\n") usb_intf_attr (bInterfaceSubClass, "%02x\n") usb_intf_attr (bInterfaceProtocol, "%02x\n") -static ssize_t show_interface_string(struct device *dev, char *buf) +static ssize_t show_interface_string(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf; struct usb_device *udev; diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 8ef8a9c..c039d2f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -633,7 +633,7 @@ static const struct usb_gadget_ops dummy_ops = { /* "function" sysfs attribute */ static ssize_t -show_function (struct device *dev, char *buf) +show_function (struct device *dev, struct device_attribute *attr, char *buf) { struct dummy *dum = gadget_dev_to_dummy (dev); @@ -1600,7 +1600,7 @@ show_urb (char *buf, size_t size, struct urb *urb) } static ssize_t -show_urbs (struct device *dev, char *buf) +show_urbs (struct device *dev, struct device_attribute *attr, char *buf) { struct usb_hcd *hcd = dev_get_drvdata (dev); struct dummy *dum = hcd_to_dummy (hcd); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 4857f0e..037a7f1 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3554,14 +3554,14 @@ static void close_all_backing_files(struct fsg_dev *fsg) } -static ssize_t show_ro(struct device *dev, char *buf) +static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *buf) { struct lun *curlun = dev_to_lun(dev); return sprintf(buf, "%d\n", curlun->ro); } -static ssize_t show_file(struct device *dev, char *buf) +static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); @@ -3589,7 +3589,7 @@ static ssize_t show_file(struct device *dev, char *buf) } -static ssize_t store_ro(struct device *dev, const char *buf, size_t count) +static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3613,7 +3613,7 @@ static ssize_t store_ro(struct device *dev, const char *buf, size_t count) return rc; } -static ssize_t store_file(struct device *dev, const char *buf, size_t count) +static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index e5457f20..e47e398 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1469,7 +1469,7 @@ static const struct usb_gadget_ops net2280_ops = { /* "function" sysfs attribute */ static ssize_t -show_function (struct device *_dev, char *buf) +show_function (struct device *_dev, struct device_attribute *attr, char *buf) { struct net2280 *dev = dev_get_drvdata (_dev); @@ -1482,7 +1482,7 @@ show_function (struct device *_dev, char *buf) static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); static ssize_t -show_registers (struct device *_dev, char *buf) +show_registers (struct device *_dev, struct device_attribute *attr, char *buf) { struct net2280 *dev; char *next; @@ -1637,7 +1637,7 @@ show_registers (struct device *_dev, char *buf) static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); static ssize_t -show_queues (struct device *_dev, char *buf) +show_queues (struct device *_dev, struct device_attribute *attr, char *buf) { struct net2280 *dev; char *next; diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 6390c57..b8b4524 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -1429,7 +1429,7 @@ done: /* "function" sysfs attribute */ static ssize_t -show_function (struct device *_dev, char *buf) +show_function (struct device *_dev, struct device_attribute *attr, char *buf) { struct pxa2xx_udc *dev = dev_get_drvdata (_dev); -- cgit v0.10.2 From 060b8845e6bea938d65ad6f89e83507e5ff4fec4 Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:44:04 -0400 Subject: [PATCH] Driver Core: drivers/usb/input/aiptek.c - drivers/zorro/zorro-sysfs.c: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index 94ce2a9..e991f7e 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -1025,7 +1025,7 @@ static int aiptek_program_tablet(struct aiptek *aiptek) /*********************************************************************** * support the 'size' file -- display support */ -static ssize_t show_tabletSize(struct device *dev, char *buf) +static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1048,7 +1048,7 @@ static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL); /*********************************************************************** * support routines for the 'product_id' file */ -static ssize_t show_tabletProductId(struct device *dev, char *buf) +static ssize_t show_tabletProductId(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1064,7 +1064,7 @@ static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL); /*********************************************************************** * support routines for the 'vendor_id' file */ -static ssize_t show_tabletVendorId(struct device *dev, char *buf) +static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1079,7 +1079,7 @@ static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL); /*********************************************************************** * support routines for the 'vendor' file */ -static ssize_t show_tabletManufacturer(struct device *dev, char *buf) +static ssize_t show_tabletManufacturer(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); int retval; @@ -1096,7 +1096,7 @@ static DEVICE_ATTR(vendor, S_IRUGO, show_tabletManufacturer, NULL); /*********************************************************************** * support routines for the 'product' file */ -static ssize_t show_tabletProduct(struct device *dev, char *buf) +static ssize_t show_tabletProduct(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); int retval; @@ -1114,7 +1114,7 @@ static DEVICE_ATTR(product, S_IRUGO, show_tabletProduct, NULL); * support routines for the 'pointer_mode' file. Note that this file * both displays current setting and allows reprogramming. */ -static ssize_t show_tabletPointerMode(struct device *dev, char *buf) +static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); char *s; @@ -1143,7 +1143,7 @@ static ssize_t show_tabletPointerMode(struct device *dev, char *buf) } static ssize_t -store_tabletPointerMode(struct device *dev, const char *buf, size_t count) +store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) @@ -1168,7 +1168,7 @@ static DEVICE_ATTR(pointer_mode, * support routines for the 'coordinate_mode' file. Note that this file * both displays current setting and allows reprogramming. */ -static ssize_t show_tabletCoordinateMode(struct device *dev, char *buf) +static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); char *s; @@ -1193,7 +1193,7 @@ static ssize_t show_tabletCoordinateMode(struct device *dev, char *buf) } static ssize_t -store_tabletCoordinateMode(struct device *dev, const char *buf, size_t count) +store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) @@ -1217,7 +1217,7 @@ static DEVICE_ATTR(coordinate_mode, * support routines for the 'tool_mode' file. Note that this file * both displays current setting and allows reprogramming. */ -static ssize_t show_tabletToolMode(struct device *dev, char *buf) +static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); char *s; @@ -1262,7 +1262,7 @@ static ssize_t show_tabletToolMode(struct device *dev, char *buf) } static ssize_t -store_tabletToolMode(struct device *dev, const char *buf, size_t count) +store_tabletToolMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) @@ -1295,7 +1295,7 @@ static DEVICE_ATTR(tool_mode, * support routines for the 'xtilt' file. Note that this file * both displays current setting and allows reprogramming. */ -static ssize_t show_tabletXtilt(struct device *dev, char *buf) +static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1311,7 +1311,7 @@ static ssize_t show_tabletXtilt(struct device *dev, char *buf) } static ssize_t -store_tabletXtilt(struct device *dev, const char *buf, size_t count) +store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); int x; @@ -1337,7 +1337,7 @@ static DEVICE_ATTR(xtilt, * support routines for the 'ytilt' file. Note that this file * both displays current setting and allows reprogramming. */ -static ssize_t show_tabletYtilt(struct device *dev, char *buf) +static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1353,7 +1353,7 @@ static ssize_t show_tabletYtilt(struct device *dev, char *buf) } static ssize_t -store_tabletYtilt(struct device *dev, const char *buf, size_t count) +store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); int y; @@ -1379,7 +1379,7 @@ static DEVICE_ATTR(ytilt, * support routines for the 'jitter' file. Note that this file * both displays current setting and allows reprogramming. */ -static ssize_t show_tabletJitterDelay(struct device *dev, char *buf) +static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1390,7 +1390,7 @@ static ssize_t show_tabletJitterDelay(struct device *dev, char *buf) } static ssize_t -store_tabletJitterDelay(struct device *dev, const char *buf, size_t count) +store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1409,7 +1409,7 @@ static DEVICE_ATTR(jitter, * support routines for the 'delay' file. Note that this file * both displays current setting and allows reprogramming. */ -static ssize_t show_tabletProgrammableDelay(struct device *dev, char *buf) +static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1421,7 +1421,7 @@ static ssize_t show_tabletProgrammableDelay(struct device *dev, char *buf) } static ssize_t -store_tabletProgrammableDelay(struct device *dev, const char *buf, size_t count) +store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1440,7 +1440,7 @@ static DEVICE_ATTR(delay, * support routines for the 'input_path' file. Note that this file * only displays current setting. */ -static ssize_t show_tabletInputDevice(struct device *dev, char *buf) +static ssize_t show_tabletInputDevice(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1457,7 +1457,7 @@ static DEVICE_ATTR(input_path, S_IRUGO, show_tabletInputDevice, NULL); * support routines for the 'event_count' file. Note that this file * only displays current setting. */ -static ssize_t show_tabletEventsReceived(struct device *dev, char *buf) +static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1473,7 +1473,7 @@ static DEVICE_ATTR(event_count, S_IRUGO, show_tabletEventsReceived, NULL); * support routines for the 'diagnostic' file. Note that this file * only displays current setting. */ -static ssize_t show_tabletDiagnosticMessage(struct device *dev, char *buf) +static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); char *retMsg; @@ -1515,7 +1515,7 @@ static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL); * support routines for the 'stylus_upper' file. Note that this file * both displays current setting and allows for setting changing. */ -static ssize_t show_tabletStylusUpper(struct device *dev, char *buf) +static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); char *s; @@ -1540,7 +1540,7 @@ static ssize_t show_tabletStylusUpper(struct device *dev, char *buf) } static ssize_t -store_tabletStylusUpper(struct device *dev, const char *buf, size_t count) +store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1565,7 +1565,7 @@ static DEVICE_ATTR(stylus_upper, * support routines for the 'stylus_lower' file. Note that this file * both displays current setting and allows for setting changing. */ -static ssize_t show_tabletStylusLower(struct device *dev, char *buf) +static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); char *s; @@ -1590,7 +1590,7 @@ static ssize_t show_tabletStylusLower(struct device *dev, char *buf) } static ssize_t -store_tabletStylusLower(struct device *dev, const char *buf, size_t count) +store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1615,7 +1615,7 @@ static DEVICE_ATTR(stylus_lower, * support routines for the 'mouse_left' file. Note that this file * both displays current setting and allows for setting changing. */ -static ssize_t show_tabletMouseLeft(struct device *dev, char *buf) +static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); char *s; @@ -1644,7 +1644,7 @@ static ssize_t show_tabletMouseLeft(struct device *dev, char *buf) } static ssize_t -store_tabletMouseLeft(struct device *dev, const char *buf, size_t count) +store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1669,7 +1669,7 @@ static DEVICE_ATTR(mouse_left, * support routines for the 'mouse_middle' file. Note that this file * both displays current setting and allows for setting changing. */ -static ssize_t show_tabletMouseMiddle(struct device *dev, char *buf) +static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); char *s; @@ -1698,7 +1698,7 @@ static ssize_t show_tabletMouseMiddle(struct device *dev, char *buf) } static ssize_t -store_tabletMouseMiddle(struct device *dev, const char *buf, size_t count) +store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1725,7 +1725,7 @@ static DEVICE_ATTR(mouse_middle, * support routines for the 'mouse_right' file. Note that this file * both displays current setting and allows for setting changing. */ -static ssize_t show_tabletMouseRight(struct device *dev, char *buf) +static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); char *s; @@ -1754,7 +1754,7 @@ static ssize_t show_tabletMouseRight(struct device *dev, char *buf) } static ssize_t -store_tabletMouseRight(struct device *dev, const char *buf, size_t count) +store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1780,7 +1780,7 @@ static DEVICE_ATTR(mouse_right, * support routines for the 'wheel' file. Note that this file * both displays current setting and allows for setting changing. */ -static ssize_t show_tabletWheel(struct device *dev, char *buf) +static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1796,7 +1796,7 @@ static ssize_t show_tabletWheel(struct device *dev, char *buf) } static ssize_t -store_tabletWheel(struct device *dev, const char *buf, size_t count) +store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1814,7 +1814,7 @@ static DEVICE_ATTR(wheel, * support routines for the 'execute' file. Note that this file * both displays current setting and allows for setting changing. */ -static ssize_t show_tabletExecute(struct device *dev, char *buf) +static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1829,7 +1829,7 @@ static ssize_t show_tabletExecute(struct device *dev, char *buf) } static ssize_t -store_tabletExecute(struct device *dev, const char *buf, size_t count) +store_tabletExecute(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1855,7 +1855,7 @@ static DEVICE_ATTR(execute, * support routines for the 'odm_code' file. Note that this file * only displays current setting. */ -static ssize_t show_tabletODMCode(struct device *dev, char *buf) +static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1871,7 +1871,7 @@ static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL); * support routines for the 'model_code' file. Note that this file * only displays current setting. */ -static ssize_t show_tabletModelCode(struct device *dev, char *buf) +static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); @@ -1887,7 +1887,7 @@ static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL); * support routines for the 'firmware_code' file. Note that this file * only displays current setting. */ -static ssize_t show_firmwareCode(struct device *dev, char *buf) +static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *attr, char *buf) { struct aiptek *aiptek = dev_get_drvdata(dev); diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c index 626e2b0..b33044d 100644 --- a/drivers/usb/misc/cytherm.c +++ b/drivers/usb/misc/cytherm.c @@ -85,7 +85,7 @@ static int vendor_command(struct usb_device *dev, unsigned char request, #define BRIGHTNESS 0x2c /* RAM location for brightness value */ #define BRIGHTNESS_SEM 0x2b /* RAM location for brightness semaphore */ -static ssize_t show_brightness(struct device *dev, char *buf) +static ssize_t show_brightness(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf = to_usb_interface(dev); struct usb_cytherm *cytherm = usb_get_intfdata(intf); @@ -93,7 +93,7 @@ static ssize_t show_brightness(struct device *dev, char *buf) return sprintf(buf, "%i", cytherm->brightness); } -static ssize_t set_brightness(struct device *dev, const char *buf, +static ssize_t set_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_interface *intf = to_usb_interface(dev); @@ -138,7 +138,7 @@ static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP, #define TEMP 0x33 /* RAM location for temperature */ #define SIGN 0x34 /* RAM location for temperature sign */ -static ssize_t show_temp(struct device *dev, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf = to_usb_interface(dev); @@ -174,7 +174,7 @@ static ssize_t show_temp(struct device *dev, char *buf) } -static ssize_t set_temp(struct device *dev, const char *buf, size_t count) +static ssize_t set_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { return count; } @@ -184,7 +184,7 @@ static DEVICE_ATTR(temp, S_IRUGO, show_temp, set_temp); #define BUTTON 0x7a -static ssize_t show_button(struct device *dev, char *buf) +static ssize_t show_button(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf = to_usb_interface(dev); @@ -215,7 +215,7 @@ static ssize_t show_button(struct device *dev, char *buf) } -static ssize_t set_button(struct device *dev, const char *buf, size_t count) +static ssize_t set_button(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { return count; } @@ -223,7 +223,7 @@ static ssize_t set_button(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(button, S_IRUGO, show_button, set_button); -static ssize_t show_port0(struct device *dev, char *buf) +static ssize_t show_port0(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf = to_usb_interface(dev); struct usb_cytherm *cytherm = usb_get_intfdata(intf); @@ -249,7 +249,7 @@ static ssize_t show_port0(struct device *dev, char *buf) } -static ssize_t set_port0(struct device *dev, const char *buf, size_t count) +static ssize_t set_port0(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_interface *intf = to_usb_interface(dev); struct usb_cytherm *cytherm = usb_get_intfdata(intf); @@ -283,7 +283,7 @@ static ssize_t set_port0(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR | S_IWGRP, show_port0, set_port0); -static ssize_t show_port1(struct device *dev, char *buf) +static ssize_t show_port1(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf = to_usb_interface(dev); struct usb_cytherm *cytherm = usb_get_intfdata(intf); @@ -309,7 +309,7 @@ static ssize_t show_port1(struct device *dev, char *buf) } -static ssize_t set_port1(struct device *dev, const char *buf, size_t count) +static ssize_t set_port1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_interface *intf = to_usb_interface(dev); struct usb_cytherm *cytherm = usb_get_intfdata(intf); diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index ddbf8e9..067a814 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -173,7 +173,7 @@ exit: } #define set_lcd_line(number) \ -static ssize_t lcd_line_##number(struct device *dev, const char *buf, size_t count) \ +static ssize_t lcd_line_##number(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ struct usb_interface *intf = to_usb_interface(dev); \ struct phidget_interfacekit *kit = usb_get_intfdata(intf); \ @@ -184,7 +184,7 @@ static DEVICE_ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number); set_lcd_line(1); set_lcd_line(2); -static ssize_t set_backlight(struct device *dev, const char *buf, size_t count) +static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_interface *intf = to_usb_interface(dev); struct phidget_interfacekit *kit = usb_get_intfdata(intf); @@ -232,7 +232,7 @@ static void remove_lcd_files(struct phidget_interfacekit *kit) } } -static ssize_t enable_lcd_files(struct device *dev, const char *buf, size_t count) +static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_interface *intf = to_usb_interface(dev); struct phidget_interfacekit *kit = usb_get_intfdata(intf); @@ -307,7 +307,7 @@ resubmit: } #define show_set_output(value) \ -static ssize_t set_output##value(struct device *dev, const char *buf, \ +static ssize_t set_output##value(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct usb_interface *intf = to_usb_interface(dev); \ @@ -324,7 +324,7 @@ static ssize_t set_output##value(struct device *dev, const char *buf, \ return retval ? retval : count; \ } \ \ -static ssize_t show_output##value(struct device *dev, char *buf) \ +static ssize_t show_output##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_interface *intf = to_usb_interface(dev); \ struct phidget_interfacekit *kit = usb_get_intfdata(intf); \ @@ -343,7 +343,7 @@ show_set_output(7); show_set_output(8); /* should be MAX_INTERFACES - 1 */ #define show_input(value) \ -static ssize_t show_input##value(struct device *dev, char *buf) \ +static ssize_t show_input##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_interface *intf = to_usb_interface(dev); \ struct phidget_interfacekit *kit = usb_get_intfdata(intf); \ @@ -362,7 +362,7 @@ show_input(7); show_input(8); /* should be MAX_INTERFACES - 1 */ #define show_sensor(value) \ -static ssize_t show_sensor##value(struct device *dev, char *buf) \ +static ssize_t show_sensor##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_interface *intf = to_usb_interface(dev); \ struct phidget_interfacekit *kit = usb_get_intfdata(intf); \ diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c index 4bd2915..b84eda6 100644 --- a/drivers/usb/misc/phidgetservo.c +++ b/drivers/usb/misc/phidgetservo.c @@ -207,7 +207,7 @@ change_position_v20(struct phidget_servo *servo, int servo_no, int degrees, } #define show_set(value) \ -static ssize_t set_servo##value (struct device *dev, \ +static ssize_t set_servo##value (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ int degrees, minutes, retval; \ @@ -233,7 +233,7 @@ static ssize_t set_servo##value (struct device *dev, \ return retval < 0 ? retval : count; \ } \ \ -static ssize_t show_servo##value (struct device *dev, char *buf) \ +static ssize_t show_servo##value (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_interface *intf = to_usb_interface (dev); \ struct phidget_servo *servo = usb_get_intfdata (intf); \ diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c index ee329d5..f6ba4c7 100644 --- a/drivers/usb/misc/usbled.c +++ b/drivers/usb/misc/usbled.c @@ -81,14 +81,14 @@ static void change_color(struct usb_led *led) } #define show_set(value) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct usb_interface *intf = to_usb_interface(dev); \ struct usb_led *led = usb_get_intfdata(intf); \ \ return sprintf(buf, "%d\n", led->value); \ } \ -static ssize_t set_##value(struct device *dev, const char *buf, size_t count) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ { \ struct usb_interface *intf = to_usb_interface(dev); \ struct usb_led *led = usb_get_intfdata(intf); \ diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3bfcc7b..d882fa3 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1218,7 +1218,7 @@ check_and_exit: * *************************************************************************** */ -static ssize_t show_latency_timer(struct device *dev, char *buf) +static ssize_t show_latency_timer(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); @@ -1245,7 +1245,7 @@ static ssize_t show_latency_timer(struct device *dev, char *buf) } /* Write a new value of the latency timer, in units of milliseconds. */ -static ssize_t store_latency_timer(struct device *dev, const char *valbuf, +static ssize_t store_latency_timer(struct device *dev, struct device_attribute *attr, const char *valbuf, size_t count) { struct usb_serial_port *port = to_usb_serial_port(dev); @@ -1276,7 +1276,7 @@ static ssize_t store_latency_timer(struct device *dev, const char *valbuf, /* Write an event character directly to the FTDI register. The ASCII value is in the low 8 bits, with the enable bit in the 9th bit. */ -static ssize_t store_event_char(struct device *dev, const char *valbuf, +static ssize_t store_event_char(struct device *dev, struct device_attribute *attr, const char *valbuf, size_t count) { struct usb_serial_port *port = to_usb_serial_port(dev); diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 1035b24..e43eddc 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -398,7 +398,7 @@ US_DO_ALL_FLAGS ***********************************************************************/ /* Output routine for the sysfs max_sectors file */ -static ssize_t show_max_sectors(struct device *dev, char *buf) +static ssize_t show_max_sectors(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); @@ -406,7 +406,7 @@ static ssize_t show_max_sectors(struct device *dev, char *buf) } /* Input routine for the sysfs max_sectors file */ -static ssize_t store_max_sectors(struct device *dev, const char *buf, +static ssize_t store_max_sectors(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct scsi_device *sdev = to_scsi_device(dev); diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 2a02328..d3c1922 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -1045,14 +1045,14 @@ static struct fb_ops gbefb_ops = { * sysfs */ -static ssize_t gbefb_show_memsize(struct device *dev, char *buf) +static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", gbe_mem_size); } static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL); -static ssize_t gbefb_show_rev(struct device *device, char *buf) +static ssize_t gbefb_show_rev(struct device *device, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", gbe_revision); } diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 58cd2ad..adcda69 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -101,7 +101,7 @@ static void(*w100fb_ssp_send)(u8 adrs, u8 data); * Sysfs functions */ -static ssize_t rotation_show(struct device *dev, char *buf) +static ssize_t rotation_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; @@ -109,7 +109,7 @@ static ssize_t rotation_show(struct device *dev, char *buf) return sprintf(buf, "%d\n",par->rotation_flag); } -static ssize_t rotation_store(struct device *dev, const char *buf, size_t count) +static ssize_t rotation_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned int rotate; struct fb_info *info = dev_get_drvdata(dev); @@ -134,7 +134,7 @@ static ssize_t rotation_store(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(rotation, 0644, rotation_show, rotation_store); -static ssize_t w100fb_reg_read(struct device *dev, const char *buf, size_t count) +static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long param; unsigned long regs; @@ -146,7 +146,7 @@ static ssize_t w100fb_reg_read(struct device *dev, const char *buf, size_t count static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read); -static ssize_t w100fb_reg_write(struct device *dev, const char *buf, size_t count) +static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long regs; unsigned long param; @@ -163,7 +163,7 @@ static ssize_t w100fb_reg_write(struct device *dev, const char *buf, size_t coun static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write); -static ssize_t fastsysclk_show(struct device *dev, char *buf) +static ssize_t fastsysclk_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; @@ -171,7 +171,7 @@ static ssize_t fastsysclk_show(struct device *dev, char *buf) return sprintf(buf, "%d\n",par->fastsysclk_mode); } -static ssize_t fastsysclk_store(struct device *dev, const char *buf, size_t count) +static ssize_t fastsysclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int param; struct fb_info *info = dev_get_drvdata(dev); diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 8d78218..24a192e 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -88,7 +88,7 @@ static void w1_slave_release(struct device *dev) complete(&sl->dev_released); } -static ssize_t w1_default_read_name(struct device *dev, char *buf) +static ssize_t w1_default_read_name(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "No family registered.\n"); } @@ -137,7 +137,7 @@ static struct device_attribute w1_slave_attribute_val = { .show = &w1_default_read_name, }; -static ssize_t w1_master_attribute_show_name(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_master *md = container_of (dev, struct w1_master, dev); ssize_t count; @@ -152,7 +152,7 @@ static ssize_t w1_master_attribute_show_name(struct device *dev, char *buf) return count; } -static ssize_t w1_master_attribute_show_pointer(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; @@ -166,14 +166,14 @@ static ssize_t w1_master_attribute_show_pointer(struct device *dev, char *buf) return count; } -static ssize_t w1_master_attribute_show_timeout(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t count; count = sprintf(buf, "%d\n", w1_timeout); return count; } -static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; @@ -187,7 +187,7 @@ static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, char return count; } -static ssize_t w1_master_attribute_show_attempts(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; @@ -201,7 +201,7 @@ static ssize_t w1_master_attribute_show_attempts(struct device *dev, char *buf) return count; } -static ssize_t w1_master_attribute_show_slave_count(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; @@ -215,7 +215,7 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, char *bu return count; } -static ssize_t w1_master_attribute_show_slaves(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 03a2de7..07fa494 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h @@ -34,10 +34,10 @@ struct w1_family_ops { - ssize_t (* rname)(struct device *, char *); + ssize_t (* rname)(struct device *, struct device_attribute *, char *); ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t); - ssize_t (* rval)(struct device *, char *); + ssize_t (* rval)(struct device *, struct device_attribute *, char *); unsigned char rvalname[MAXNAMELEN]; }; diff --git a/drivers/w1/w1_smem.c b/drivers/w1/w1_smem.c index a54e425..674eb75 100644 --- a/drivers/w1/w1_smem.c +++ b/drivers/w1/w1_smem.c @@ -36,8 +36,8 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Evgeniy Polyakov "); MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family."); -static ssize_t w1_smem_read_name(struct device *, char *); -static ssize_t w1_smem_read_val(struct device *, char *); +static ssize_t w1_smem_read_name(struct device *, struct device_attribute *attr, char *); +static ssize_t w1_smem_read_val(struct device *, struct device_attribute *attr, char *); static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t); static struct w1_family_ops w1_smem_fops = { @@ -47,14 +47,14 @@ static struct w1_family_ops w1_smem_fops = { .rvalname = "id", }; -static ssize_t w1_smem_read_name(struct device *dev, char *buf) +static ssize_t w1_smem_read_name(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_slave *sl = container_of(dev, struct w1_slave, dev); return sprintf(buf, "%s\n", sl->name); } -static ssize_t w1_smem_read_val(struct device *dev, char *buf) +static ssize_t w1_smem_read_val(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_slave *sl = container_of(dev, struct w1_slave, dev); int i; diff --git a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c index 0b18178..70310f7 100644 --- a/drivers/w1/w1_therm.c +++ b/drivers/w1/w1_therm.c @@ -42,8 +42,8 @@ static u8 bad_roms[][9] = { {} }; -static ssize_t w1_therm_read_name(struct device *, char *); -static ssize_t w1_therm_read_temp(struct device *, char *); +static ssize_t w1_therm_read_name(struct device *, struct device_attribute *attr, char *); +static ssize_t w1_therm_read_temp(struct device *, struct device_attribute *attr, char *); static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t); static struct w1_family_ops w1_therm_fops = { @@ -53,7 +53,7 @@ static struct w1_family_ops w1_therm_fops = { .rvalname = "temp1_input", }; -static ssize_t w1_therm_read_name(struct device *dev, char *buf) +static ssize_t w1_therm_read_name(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_slave *sl = container_of(dev, struct w1_slave, dev); @@ -77,7 +77,7 @@ static inline int w1_convert_temp(u8 rom[9]) return t; } -static ssize_t w1_therm_read_temp(struct device *dev, char *buf) +static ssize_t w1_therm_read_temp(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_slave *sl = container_of(dev, struct w1_slave, dev); diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c index dad03fc..04ca884 100644 --- a/drivers/zorro/zorro-sysfs.c +++ b/drivers/zorro/zorro-sysfs.c @@ -21,7 +21,7 @@ /* show configuration fields */ #define zorro_config_attr(name, field, format_string) \ static ssize_t \ -show_##name(struct device *dev, char *buf) \ +show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct zorro_dev *z; \ \ @@ -36,7 +36,7 @@ zorro_config_attr(serial, rom.er_SerialNumber, "0x%08x\n"); zorro_config_attr(slotaddr, slotaddr, "0x%04x\n"); zorro_config_attr(slotsize, slotsize, "0x%04x\n"); -static ssize_t zorro_show_resource(struct device *dev, char *buf) +static ssize_t zorro_show_resource(struct device *dev, struct device_attribute *attr, char *buf) { struct zorro_dev *z = to_zorro_dev(dev); -- cgit v0.10.2 From f2d03e1b3f00f1c5971463ab0101bef0c521ad3b Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 06:44:59 -0400 Subject: [PATCH] Driver Core: include: update device attribute callbacks Signed-off-by: Yani Ioannou Signed-off-by: Greg Kroah-Hartman diff --git a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h index b98db3c..c726f18 100644 --- a/include/asm-ppc/ocp.h +++ b/include/asm-ppc/ocp.h @@ -189,7 +189,7 @@ extern void ocp_for_each_device(void(*callback)(struct ocp_device *, void *arg), /* Sysfs support */ #define OCP_SYSFS_ADDTL(type, format, name, field) \ static ssize_t \ -show_##name##_##field(struct device *dev, char *buf) \ +show_##name##_##field(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct ocp_device *odev = to_ocp_dev(dev); \ type *add = odev->def->additions; \ -- cgit v0.10.2 From 0a3e7eeabc9f76b7496488aad2d11626ff6a2a4f Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Tue, 17 May 2005 22:59:05 -0400 Subject: [PATCH] I2C: add i2c sensor_device_attribute and macros This patch creates a new header with a potential standard i2c sensor attribute type (which simply includes an int representing the sensor number/index) and the associated macros, SENSOR_DEVICE_ATTR to define a static attribute and to_sensor_dev_attr to get a sensor_device_attribute reference from an embedded device_attribute reference. Signed-off-by: Yani Ioannou diff --git a/include/linux/i2c-sysfs.h b/include/linux/i2c-sysfs.h new file mode 100644 index 0000000..d7bf6ce --- /dev/null +++ b/include/linux/i2c-sysfs.h @@ -0,0 +1,36 @@ +/* + * i2c-sysfs.h - i2c chip driver sysfs defines + * + * Copyright (C) 2005 Yani Ioannou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _LINUX_I2C_SYSFS_H +#define _LINUX_I2C_SYSFS_H + +struct sensor_device_attribute{ + struct device_attribute dev_attr; + int index; +}; +#define to_sensor_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct sensor_device_attribute, dev_attr) + +#define SENSOR_DEVICE_ATTR(_name,_mode,_show,_store,_index) \ +struct sensor_device_attribute sensor_dev_attr_##_name = { \ + .dev_attr = __ATTR(_name,_mode,_show,_store), \ + .index = _index, \ +} + +#endif /* _LINUX_I2C_SYSFS_H */ -- cgit v0.10.2 From 050480f12aeab62d39a1a07546606a47217ebefa Mon Sep 17 00:00:00 2001 From: Yani Ioannou Date: Sun, 5 Jun 2005 10:51:46 +0200 Subject: [PATCH] I2C: drivers/i2c/chips/adm1026.c: use dynamic sysfs callbacks Finally (phew!) this patch demonstrates how to adapt the adm1026 to take advantage of the new callbacks, and the i2c-sysfs.h defined structure/macros. Most of the other sensor/hwmon drivers could be updated in the same way. The odd few exceptions (bmcsensors for example) however might be better off with their own custom attribute structure. Signed-off-by: Yani Ioannou Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c index c127bd9..b15fafe 100644 --- a/drivers/i2c/chips/adm1026.c +++ b/drivers/i2c/chips/adm1026.c @@ -30,6 +30,7 @@ #include #include #include +#include #include /* Addresses to scan */ @@ -711,19 +712,27 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) return data; } -static ssize_t show_in(struct device *dev, char *buf, int nr) +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr])); } -static ssize_t show_in_min(struct device *dev, char *buf, int nr) +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr])); } -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -734,14 +743,19 @@ static ssize_t set_in_min(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t show_in_max(struct device *dev, char *buf, int nr) +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr])); } -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -753,34 +767,13 @@ static ssize_t set_in_max(struct device *dev, const char *buf, return count; } -#define in_reg(offset) \ -static ssize_t show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static ssize_t show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); +#define in_reg(offset) \ +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in, \ + NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset); in_reg(0); @@ -843,30 +836,38 @@ static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, c return count; } -static DEVICE_ATTR(in16_input, S_IRUGO, show_in16, NULL); -static DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min, set_in16_min); -static DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max, set_in16_max); +static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in16, NULL, 16); +static SENSOR_DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min, set_in16_min, 16); +static SENSOR_DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max, set_in16_max, 16); /* Now add fan read/write functions */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], data->fan_div[nr])); } -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], data->fan_div[nr])); } -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -879,23 +880,11 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, return count; } -#define fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); +#define fan_offset(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \ + offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); fan_offset(1); fan_offset(2); @@ -926,14 +915,19 @@ static void fixup_fan_min(struct device *dev, int fan, int old_div) } /* Now add fan_div read/write functions */ -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", data->fan_div[nr]); } -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val,orig_div,new_div,shift; @@ -967,17 +961,8 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, } #define fan_offset_div(offset) \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_div, set_fan_##offset##_div); +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_div, set_fan_div, offset - 1); fan_offset_div(1); fan_offset_div(2); @@ -989,19 +974,27 @@ fan_offset_div(7); fan_offset_div(8); /* Temps */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr])); } -static ssize_t show_temp_min(struct device *dev, char *buf, int nr) +static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr])); } -static ssize_t set_temp_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -1013,14 +1006,19 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t show_temp_max(struct device *dev, char *buf, int nr) +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr])); } -static ssize_t set_temp_max(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -1032,48 +1030,34 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, up(&data->update_lock); return count; } -#define temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_max(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max); + +#define temp_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ + NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_min, set_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, offset - 1); temp_reg(1); temp_reg(2); temp_reg(3); -static ssize_t show_temp_offset(struct device *dev, char *buf, int nr) +static ssize_t show_temp_offset(struct device *dev, + struct device_attribute *attr, char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_offset[nr])); } -static ssize_t set_temp_offset(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_temp_offset(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -1086,46 +1070,45 @@ static ssize_t set_temp_offset(struct device *dev, const char *buf, return count; } -#define temp_offset_reg(offset) \ -static ssize_t show_temp_##offset##_offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_offset(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_offset(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_offset, set_temp_##offset##_offset); +#define temp_offset_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR, \ + show_temp_offset, set_temp_offset, offset - 1); temp_offset_reg(1); temp_offset_reg(2); temp_offset_reg(3); -static ssize_t show_temp_auto_point1_temp_hyst(struct device *dev, char *buf, - int nr) +static ssize_t show_temp_auto_point1_temp_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG( ADM1026_FAN_ACTIVATION_TEMP_HYST + data->temp_tmin[nr])); } -static ssize_t show_temp_auto_point2_temp(struct device *dev, char *buf, - int nr) +static ssize_t show_temp_auto_point2_temp(struct device *dev, + struct device_attribute *attr, char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr] + ADM1026_FAN_CONTROL_TEMP_RANGE)); } -static ssize_t show_temp_auto_point1_temp(struct device *dev, char *buf, - int nr) +static ssize_t show_temp_auto_point1_temp(struct device *dev, + struct device_attribute *attr, char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr])); } -static ssize_t set_temp_auto_point1_temp(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_temp_auto_point1_temp(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -1138,46 +1121,27 @@ static ssize_t set_temp_auto_point1_temp(struct device *dev, const char *buf, return count; } -#define temp_auto_point(offset) \ -static ssize_t show_temp##offset##_auto_point1_temp (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_point1_temp(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_point1_temp (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_point1_temp(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_point1_temp_hyst (struct device \ - *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_auto_point1_temp_hyst(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_point2_temp (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_point2_temp(dev, buf, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_auto_point1_temp, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_point1_temp, \ - set_temp##offset##_auto_point1_temp); \ -static DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO, \ - show_temp##offset##_auto_point1_temp_hyst, NULL); \ -static DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO, \ - show_temp##offset##_auto_point2_temp, NULL); +#define temp_auto_point(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp, S_IRUGO | S_IWUSR, \ + show_temp_auto_point1_temp, set_temp_auto_point1_temp, \ + offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO, \ + show_temp_auto_point1_temp_hyst, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO, \ + show_temp_auto_point2_temp, NULL, offset - 1); temp_auto_point(1); temp_auto_point(2); temp_auto_point(3); -static ssize_t show_temp_crit_enable(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_crit_enable(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", (data->config1 & CFG1_THERM_HOT) >> 4); } -static ssize_t set_temp_crit_enable(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_temp_crit_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); @@ -1193,24 +1157,27 @@ static ssize_t set_temp_crit_enable(struct device *dev, struct device_attribute return count; } -static DEVICE_ATTR(temp1_crit_enable, S_IRUGO | S_IWUSR, - show_temp_crit_enable, set_temp_crit_enable); - -static DEVICE_ATTR(temp2_crit_enable, S_IRUGO | S_IWUSR, - show_temp_crit_enable, set_temp_crit_enable); - -static DEVICE_ATTR(temp3_crit_enable, S_IRUGO | S_IWUSR, +#define temp_crit_enable(offset) \ +static DEVICE_ATTR(temp##offset##_crit_enable, S_IRUGO | S_IWUSR, \ show_temp_crit_enable, set_temp_crit_enable); +temp_crit_enable(1); +temp_crit_enable(2); +temp_crit_enable(3); -static ssize_t show_temp_crit(struct device *dev, char *buf, int nr) +static ssize_t show_temp_crit(struct device *dev, + struct device_attribute *attr, char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_crit[nr])); } -static ssize_t set_temp_crit(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -1223,18 +1190,9 @@ static ssize_t set_temp_crit(struct device *dev, const char *buf, return count; } -#define temp_crit_reg(offset) \ -static ssize_t show_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_crit(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_crit(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_crit, set_temp_##offset##_crit); +#define temp_crit_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ + show_temp_crit, set_temp_crit, offset - 1); temp_crit_reg(1); temp_crit_reg(2); @@ -1597,114 +1555,114 @@ int adm1026_detect(struct i2c_adapter *adapter, int address, adm1026_init_client(new_client); /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in6_max); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in7_input); - device_create_file(&new_client->dev, &dev_attr_in7_max); - device_create_file(&new_client->dev, &dev_attr_in7_min); - device_create_file(&new_client->dev, &dev_attr_in8_input); - device_create_file(&new_client->dev, &dev_attr_in8_max); - device_create_file(&new_client->dev, &dev_attr_in8_min); - device_create_file(&new_client->dev, &dev_attr_in9_input); - device_create_file(&new_client->dev, &dev_attr_in9_max); - device_create_file(&new_client->dev, &dev_attr_in9_min); - device_create_file(&new_client->dev, &dev_attr_in10_input); - device_create_file(&new_client->dev, &dev_attr_in10_max); - device_create_file(&new_client->dev, &dev_attr_in10_min); - device_create_file(&new_client->dev, &dev_attr_in11_input); - device_create_file(&new_client->dev, &dev_attr_in11_max); - device_create_file(&new_client->dev, &dev_attr_in11_min); - device_create_file(&new_client->dev, &dev_attr_in12_input); - device_create_file(&new_client->dev, &dev_attr_in12_max); - device_create_file(&new_client->dev, &dev_attr_in12_min); - device_create_file(&new_client->dev, &dev_attr_in13_input); - device_create_file(&new_client->dev, &dev_attr_in13_max); - device_create_file(&new_client->dev, &dev_attr_in13_min); - device_create_file(&new_client->dev, &dev_attr_in14_input); - device_create_file(&new_client->dev, &dev_attr_in14_max); - device_create_file(&new_client->dev, &dev_attr_in14_min); - device_create_file(&new_client->dev, &dev_attr_in15_input); - device_create_file(&new_client->dev, &dev_attr_in15_max); - device_create_file(&new_client->dev, &dev_attr_in15_min); - device_create_file(&new_client->dev, &dev_attr_in16_input); - device_create_file(&new_client->dev, &dev_attr_in16_max); - device_create_file(&new_client->dev, &dev_attr_in16_min); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan3_div); - device_create_file(&new_client->dev, &dev_attr_fan3_min); - device_create_file(&new_client->dev, &dev_attr_fan4_input); - device_create_file(&new_client->dev, &dev_attr_fan4_div); - device_create_file(&new_client->dev, &dev_attr_fan4_min); - device_create_file(&new_client->dev, &dev_attr_fan5_input); - device_create_file(&new_client->dev, &dev_attr_fan5_div); - device_create_file(&new_client->dev, &dev_attr_fan5_min); - device_create_file(&new_client->dev, &dev_attr_fan6_input); - device_create_file(&new_client->dev, &dev_attr_fan6_div); - device_create_file(&new_client->dev, &dev_attr_fan6_min); - device_create_file(&new_client->dev, &dev_attr_fan7_input); - device_create_file(&new_client->dev, &dev_attr_fan7_div); - device_create_file(&new_client->dev, &dev_attr_fan7_min); - device_create_file(&new_client->dev, &dev_attr_fan8_input); - device_create_file(&new_client->dev, &dev_attr_fan8_div); - device_create_file(&new_client->dev, &dev_attr_fan8_min); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp1_offset); - device_create_file(&new_client->dev, &dev_attr_temp2_offset); - device_create_file(&new_client->dev, &dev_attr_temp3_offset); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in11_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in11_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in11_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in12_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in12_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in12_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in13_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in13_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in13_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in14_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in14_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in14_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in15_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in15_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in15_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in16_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in16_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in16_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan4_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan4_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan4_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan5_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan5_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan5_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan6_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan6_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan6_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan7_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan7_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan7_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan8_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan8_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan8_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_offset.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_offset.dev_attr); device_create_file(&new_client->dev, - &dev_attr_temp1_auto_point1_temp); + &sensor_dev_attr_temp1_auto_point1_temp.dev_attr); device_create_file(&new_client->dev, - &dev_attr_temp2_auto_point1_temp); + &sensor_dev_attr_temp2_auto_point1_temp.dev_attr); device_create_file(&new_client->dev, - &dev_attr_temp3_auto_point1_temp); + &sensor_dev_attr_temp3_auto_point1_temp.dev_attr); device_create_file(&new_client->dev, - &dev_attr_temp1_auto_point1_temp_hyst); + &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr); device_create_file(&new_client->dev, - &dev_attr_temp2_auto_point1_temp_hyst); + &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr); device_create_file(&new_client->dev, - &dev_attr_temp3_auto_point1_temp_hyst); + &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr); device_create_file(&new_client->dev, - &dev_attr_temp1_auto_point2_temp); + &sensor_dev_attr_temp1_auto_point2_temp.dev_attr); device_create_file(&new_client->dev, - &dev_attr_temp2_auto_point2_temp); + &sensor_dev_attr_temp2_auto_point2_temp.dev_attr); device_create_file(&new_client->dev, - &dev_attr_temp3_auto_point2_temp); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); + &sensor_dev_attr_temp3_auto_point2_temp.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr); device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable); device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable); device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable); -- cgit v0.10.2 From 6fa5c828c7fb6beef7035864bd2b18e7386fbdd5 Mon Sep 17 00:00:00 2001 From: Maneesh Soni Date: Tue, 31 May 2005 10:38:12 +0530 Subject: [PATCH] sysfs-iattr: attach sysfs_dirent before new inode o The following patch makes sure to attach sysfs_dirent to the dentry before allocation a new inode through sysfs_create(). This change is done as preparatory work for implementing ->i_op->setattr() functionality for sysfs objects. Signed-off-by: Maneesh Soni Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index fe19821..5cf3270 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -101,18 +101,19 @@ static int create_dir(struct kobject * k, struct dentry * p, down(&p->d_inode->i_sem); *d = sysfs_get_dentry(p,n); if (!IS_ERR(*d)) { - error = sysfs_create(*d, mode, init_dir); + error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR); if (!error) { - error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, - SYSFS_DIR); + error = sysfs_create(*d, mode, init_dir); if (!error) { p->d_inode->i_nlink++; (*d)->d_op = &sysfs_dentry_ops; d_rehash(*d); } } - if (error && (error != -EEXIST)) + if (error && (error != -EEXIST)) { + sysfs_put((*d)->d_fsdata); d_drop(*d); + } dput(*d); } else error = PTR_ERR(*d); @@ -171,17 +172,19 @@ static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry) init = init_file; } + dentry->d_fsdata = sysfs_get(sd); + sd->s_dentry = dentry; error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init); - if (error) + if (error) { + sysfs_put(sd); return error; + } if (bin_attr) { dentry->d_inode->i_size = bin_attr->size; dentry->d_inode->i_fop = &bin_fops; } dentry->d_op = &sysfs_dentry_ops; - dentry->d_fsdata = sysfs_get(sd); - sd->s_dentry = dentry; d_rehash(dentry); return 0; @@ -191,13 +194,15 @@ static int sysfs_attach_link(struct sysfs_dirent * sd, struct dentry * dentry) { int err = 0; + dentry->d_fsdata = sysfs_get(sd); + sd->s_dentry = dentry; err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink); if (!err) { dentry->d_op = &sysfs_dentry_ops; - dentry->d_fsdata = sysfs_get(sd); - sd->s_dentry = dentry; d_rehash(dentry); - } + } else + sysfs_put(sd); + return err; } -- cgit v0.10.2 From 988d186de5b6966a71a8cc52e6cb4895fd2f7799 Mon Sep 17 00:00:00 2001 From: Maneesh Soni Date: Tue, 31 May 2005 10:39:14 +0530 Subject: [PATCH] sysfs-iattr: add sysfs_setattr o This adds ->i_op->setattr VFS method for sysfs inodes. The changed attribues are saved in the persistent sysfs_dirent structure as a pointer to struct iattr. The struct iattr is allocated only for those sysfs_dirent's for which default attributes are getting changed. Thanks to Jon Smirl for this suggestion. Signed-off-by: Maneesh Soni Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5cf3270..37d7a68 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -233,6 +233,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, struct inode_operations sysfs_dir_inode_operations = { .lookup = sysfs_lookup, + .setattr = sysfs_setattr, }; static void remove_dir(struct dentry * d) diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index aff7b2d..400c90b 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -26,6 +26,71 @@ static struct backing_dev_info sysfs_backing_dev_info = { .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, }; +static struct inode_operations sysfs_inode_operations ={ + .setattr = sysfs_setattr, +}; + +int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) +{ + struct inode * inode = dentry->d_inode; + struct sysfs_dirent * sd = dentry->d_fsdata; + struct iattr * sd_iattr; + unsigned int ia_valid = iattr->ia_valid; + int error; + + if (!sd) + return -EINVAL; + + sd_iattr = sd->s_iattr; + + error = inode_change_ok(inode, iattr); + if (error) + return error; + + error = inode_setattr(inode, iattr); + if (error) + return error; + + if (!sd_iattr) { + /* setting attributes for the first time, allocate now */ + sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL); + if (!sd_iattr) + return -ENOMEM; + /* assign default attributes */ + memset(sd_iattr, 0, sizeof(struct iattr)); + sd_iattr->ia_mode = sd->s_mode; + sd_iattr->ia_uid = 0; + sd_iattr->ia_gid = 0; + sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; + sd->s_iattr = sd_iattr; + } + + /* attributes were changed atleast once in past */ + + if (ia_valid & ATTR_UID) + sd_iattr->ia_uid = iattr->ia_uid; + if (ia_valid & ATTR_GID) + sd_iattr->ia_gid = iattr->ia_gid; + if (ia_valid & ATTR_ATIME) + sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, + inode->i_sb->s_time_gran); + if (ia_valid & ATTR_MTIME) + sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, + inode->i_sb->s_time_gran); + if (ia_valid & ATTR_CTIME) + sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, + inode->i_sb->s_time_gran); + if (ia_valid & ATTR_MODE) { + umode_t mode = iattr->ia_mode; + + if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) + mode &= ~S_ISGID; + sd_iattr->ia_mode = mode; + } + + return error; +} + struct inode * sysfs_new_inode(mode_t mode) { struct inode * inode = new_inode(sysfs_sb); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index a8a24a0..e8e9f0c 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -17,6 +17,7 @@ extern void sysfs_remove_subdir(struct dentry *); extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd); extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent); +extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); extern struct rw_semaphore sysfs_rename_sem; extern struct super_block * sysfs_sb; @@ -75,6 +76,7 @@ static inline void release_sysfs_dirent(struct sysfs_dirent * sd) kobject_put(sl->target_kobj); kfree(sl); } + kfree(sd->s_iattr); kmem_cache_free(sysfs_dir_cachep, sd); } diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index d9cd2d3..392da5a 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -73,6 +73,7 @@ struct sysfs_dirent { int s_type; umode_t s_mode; struct dentry * s_dentry; + struct iattr * s_iattr; }; #define SYSFS_ROOT 0x0001 -- cgit v0.10.2 From 8215534ce7d073423bfa9c17405c43ab7636ca03 Mon Sep 17 00:00:00 2001 From: Maneesh Soni Date: Tue, 31 May 2005 10:39:52 +0530 Subject: [PATCH] sysfs-iattr: set inode attributes o Following patch sets the attributes for newly allocated inodes for sysfs objects. If the object has non-default attributes, inode attributes are set as saved in sysfs_dirent->s_iattr, pointer to struct iattr. Signed-off-by: Maneesh Soni Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 400c90b..565cac1 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -91,18 +91,42 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) return error; } -struct inode * sysfs_new_inode(mode_t mode) +static inline void set_default_inode_attr(struct inode * inode, mode_t mode) +{ + inode->i_mode = mode; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; +} + +static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) +{ + inode->i_mode = iattr->ia_mode; + inode->i_uid = iattr->ia_uid; + inode->i_gid = iattr->ia_gid; + inode->i_atime = iattr->ia_atime; + inode->i_mtime = iattr->ia_mtime; + inode->i_ctime = iattr->ia_ctime; +} + +struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd) { struct inode * inode = new_inode(sysfs_sb); if (inode) { - inode->i_mode = mode; - inode->i_uid = 0; - inode->i_gid = 0; inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; + inode->i_op = &sysfs_inode_operations; + + if (sd->s_iattr) { + /* sysfs_dirent has non-default attributes + * get them for the new inode from persistent copy + * in sysfs_dirent + */ + set_inode_attr(inode, sd->s_iattr); + } else + set_default_inode_attr(inode, mode); } return inode; } @@ -113,7 +137,8 @@ int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) struct inode * inode = NULL; if (dentry) { if (!dentry->d_inode) { - if ((inode = sysfs_new_inode(mode))) { + struct sysfs_dirent * sd = dentry->d_fsdata; + if ((inode = sysfs_new_inode(mode, sd))) { if (dentry->d_parent && dentry->d_parent->d_inode) { struct inode *p_inode = dentry->d_parent->d_inode; p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 5c805bb..f1117e8 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -28,6 +28,7 @@ static struct sysfs_dirent sysfs_root = { .s_children = LIST_HEAD_INIT(sysfs_root.s_children), .s_element = NULL, .s_type = SYSFS_ROOT, + .s_iattr = NULL, }; static int sysfs_fill_super(struct super_block *sb, void *data, int silent) @@ -42,7 +43,8 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran = 1; sysfs_sb = sb; - inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO); + inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, + &sysfs_root); if (inode) { inode->i_op = &sysfs_dir_inode_operations; inode->i_fop = &sysfs_dir_operations; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index e8e9f0c..29da6f5 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -2,7 +2,7 @@ extern struct vfsmount * sysfs_mount; extern kmem_cache_t *sysfs_dir_cachep; -extern struct inode * sysfs_new_inode(mode_t mode); +extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, -- cgit v0.10.2 From 42b16c051c3f462095fb8c9bad1bc05b34518cb9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 31 May 2005 17:08:49 +1000 Subject: [PATCH] Driver core: Don't "lose" devices on suspend on failure I think we need this patch or we might "lose" devices to the dpm_irq_off list if a failure occurs during the suspend process. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 807e13f..2ccee37 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -114,8 +114,19 @@ int device_suspend(pm_message_t state) put_device(dev); } up(&dpm_list_sem); - if (error) + if (error) { + /* we failed... before resuming, bring back devices from + * dpm_off_irq list back to main dpm_off list, we do want + * to call resume() on them, in case they partially suspended + * despite returning -EAGAIN + */ + while (!list_empty(&dpm_off_irq)) { + struct list_head * entry = dpm_off_irq.next; + list_del(entry); + list_add(entry, &dpm_off); + } dpm_resume(); + } up(&dpm_sem); return error; } -- cgit v0.10.2 From 9d9d27fb651a7c95a46f276bacb4329db47470a6 Mon Sep 17 00:00:00 2001 From: Jon Smirl Date: Tue, 14 Jun 2005 09:54:54 -0400 Subject: [PATCH] SYSFS: fix PAGE_SIZE check Without this change I can't set an attribute exactly PAGE_SIZE in length. There is no need for zero termination because the interface uses lengths. From: Jon Smirl Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 1481cae..849aac1 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -182,7 +182,7 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t return -ENOMEM; if (count >= PAGE_SIZE) - count = PAGE_SIZE - 1; + count = PAGE_SIZE; error = copy_from_user(buffer->page,buf,count); buffer->needs_read_fill = 1; return error ? -EFAULT : count; -- cgit v0.10.2 From 4893e9d1cfeb614b5155c43eefbb338b4f02cb34 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 19 Jun 2005 12:21:43 +0200 Subject: [PATCH] USB: fix show_modalias() function due to attribute change Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index c1b8e69..740cb4c 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -286,7 +286,7 @@ static ssize_t show_interface_string(struct device *dev, struct device_attribute } static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); -static ssize_t show_modalias(struct device *dev, char *buf) +static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf; struct usb_device *udev; -- cgit v0.10.2 From 87c8a4433b608261a9becdb0ce2d2f2ed4b71d05 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 19 Jun 2005 12:21:43 +0200 Subject: [PATCH] PCI: fix show_modalias() function due to attribute change Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 8b79609..a15f940 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -73,7 +73,7 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf) return (str - buf); } -static ssize_t modalias_show(struct device *dev, char *buf) +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pci_dev = to_pci_dev(dev); -- cgit v0.10.2 From b74e2159c9849fb97659c6dc47ad706f702b22b9 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Tue, 21 Jun 2005 13:21:49 +1000 Subject: [XFS] Add a get/set interface for XFS project identifiers. SGI-PV: 932952 SGI-Modid: xfs-linux:xfs-kern:21938a Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 69809ee..df17d93 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -777,6 +777,8 @@ xfs_ioctl( case XFS_IOC_GETVERSION: case XFS_IOC_GETXFLAGS: case XFS_IOC_SETXFLAGS: + case XFS_IOC_GETPROJID: + case XFS_IOC_SETPROJID: case XFS_IOC_FSGETXATTR: case XFS_IOC_FSSETXATTR: case XFS_IOC_FSGETXATTRA: @@ -1258,6 +1260,26 @@ xfs_ioc_xattr( return 0; } + case XFS_IOC_GETPROJID: { + va.va_mask = XFS_AT_PROJID; + VOP_GETATTR(vp, &va, 0, NULL, error); + if (error) + return -error; + if (copy_to_user(arg, &va.va_projid, sizeof(va.va_projid))) + return -XFS_ERROR(EFAULT); + return 0; + } + + case XFS_IOC_SETPROJID: { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + va.va_mask = XFS_AT_PROJID; + if (copy_from_user(&va.va_projid, arg, sizeof(va.va_projid))) + return -XFS_ERROR(EFAULT); + VOP_SETATTR(vp, &va, 0, NULL, error); + return -error; + } + default: return -ENOTTY; } diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 0f8f138..be72aca 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -100,6 +100,8 @@ __linvfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg) case XFS_IOC_GETBMAP: case XFS_IOC_GETBMAPA: case XFS_IOC_GETBMAPX: + case XFS_IOC_SETPROJID: + case XFS_IOC_GETPROJID: /* not handled case XFS_IOC_FD_TO_HANDLE: case XFS_IOC_PATH_TO_HANDLE: diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 00466c3..a6e57c6 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -426,7 +426,7 @@ typedef struct vattr { u_long va_extsize; /* file extent size */ u_long va_nextents; /* number of extents in file */ u_long va_anextents; /* number of attr extents in file */ - int va_projid; /* project id */ + prid_t va_projid; /* project id */ } vattr_t; /* diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index 6ee8443..a7bd468 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h @@ -477,6 +477,8 @@ typedef struct xfs_handle { /* XFS_IOC_SETBIOSIZE ---- deprecated 46 */ /* XFS_IOC_GETBIOSIZE ---- deprecated 47 */ #define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) +#define XFS_IOC_SETPROJID _IOWR('X', 57, __uint32_t) +#define XFS_IOC_GETPROJID _IOWR('X', 58, __uint32_t) /* * ioctl commands that replace IRIX syssgi()'s diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h index e4bf711..16f5371 100644 --- a/fs/xfs/xfs_types.h +++ b/fs/xfs/xfs_types.h @@ -55,7 +55,7 @@ typedef signed long long int __int64_t; typedef unsigned long long int __uint64_t; typedef enum { B_FALSE,B_TRUE } boolean_t; -typedef __int64_t prid_t; /* project ID */ +typedef __uint32_t prid_t; /* project ID */ typedef __uint32_t inst_t; /* an instruction */ typedef __s64 xfs_off_t; /* type */ -- cgit v0.10.2 From 6fac0cb46bc4c50d6cbc5998ad206435f39fb00f Mon Sep 17 00:00:00 2001 From: Dean Roehrich Date: Tue, 21 Jun 2005 14:07:45 +1000 Subject: [XFS] coordinate mmap calls with xfs_dm_punch_hole SGI-PV: 933551 SGI-Modid: xfs-linux:xfs-kern:190622a Signed-off-by: Dean Roehrich Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 24fa3b1..f1ce432 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -57,7 +57,9 @@ #include static struct vm_operations_struct linvfs_file_vm_ops; - +#ifdef CONFIG_XFS_DMAPI +static struct vm_operations_struct linvfs_dmapi_file_vm_ops; +#endif STATIC inline ssize_t __linvfs_read( @@ -388,6 +390,14 @@ done: return -error; } +#ifdef CONFIG_XFS_DMAPI +STATIC void +linvfs_mmap_close( + struct vm_area_struct *vma) +{ + xfs_dm_mm_put(vma); +} +#endif /* CONFIG_XFS_DMAPI */ STATIC int linvfs_file_mmap( @@ -399,16 +409,19 @@ linvfs_file_mmap( vattr_t va = { .va_mask = XFS_AT_UPDATIME }; int error; + vma->vm_ops = &linvfs_file_vm_ops; + if (vp->v_vfsp->vfs_flag & VFS_DMI) { xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp); error = -XFS_SEND_MMAP(mp, vma, 0); if (error) return error; +#ifdef CONFIG_XFS_DMAPI + vma->vm_ops = &linvfs_dmapi_file_vm_ops; +#endif } - vma->vm_ops = &linvfs_file_vm_ops; - VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error); if (!error) vn_revalidate(vp); /* update Linux inode flags */ @@ -609,7 +622,15 @@ struct file_operations linvfs_dir_operations = { static struct vm_operations_struct linvfs_file_vm_ops = { .nopage = filemap_nopage, .populate = filemap_populate, +}; + +#ifdef CONFIG_XFS_DMAPI +static struct vm_operations_struct linvfs_dmapi_file_vm_ops = { + .close = linvfs_mmap_close, + .nopage = filemap_nopage, + .populate = filemap_populate, #ifdef HAVE_VMOP_MPROTECT .mprotect = linvfs_mprotect, #endif }; +#endif /* CONFIG_XFS_DMAPI */ diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h index 55ae3e6..16cf9f7 100644 --- a/fs/xfs/xfs_dmapi.h +++ b/fs/xfs/xfs_dmapi.h @@ -209,4 +209,8 @@ void xfs_dm_exit(struct file_system_type *); #define XFS_DM_EXIT(fstype) #endif +#define HAVE_XFS_DM_MM +int xfs_dm_mm_get(struct vm_area_struct *vma); +void xfs_dm_mm_put(struct vm_area_struct *vma); + #endif /* __XFS_DMAPI_H__ */ -- cgit v0.10.2 -- cgit v0.10.2 -- cgit v0.10.2 -- cgit v0.10.2 From 23ea4032c875fc75c2363a9bcaba87cfb134ff68 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:14:01 +1000 Subject: [XFS] rename various pagebuf symbols to xfsbuf SGI-PV: 908809 SGI-Modid: xfs-linux:xfs-kern:192348a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 997963e5..f5676ed 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -61,12 +61,13 @@ * File wide globals */ -STATIC kmem_cache_t *pagebuf_cache; +STATIC kmem_cache_t *pagebuf_zone; STATIC kmem_shaker_t pagebuf_shake; -STATIC int pagebuf_daemon_wakeup(int, unsigned int); +STATIC int xfsbufd_wakeup(int, unsigned int); STATIC void pagebuf_delwri_queue(xfs_buf_t *, int); -STATIC struct workqueue_struct *pagebuf_logio_workqueue; -STATIC struct workqueue_struct *pagebuf_dataio_workqueue; + +STATIC struct workqueue_struct *xfslogd_workqueue; +STATIC struct workqueue_struct *xfsdatad_workqueue; /* * Pagebuf debugging @@ -123,9 +124,9 @@ ktrace_t *pagebuf_trace_buf; #define pagebuf_allocate(flags) \ - kmem_zone_alloc(pagebuf_cache, pb_to_km(flags)) + kmem_zone_alloc(pagebuf_zone, pb_to_km(flags)) #define pagebuf_deallocate(pb) \ - kmem_zone_free(pagebuf_cache, (pb)); + kmem_zone_free(pagebuf_zone, (pb)); /* * Page Region interfaces. @@ -425,7 +426,7 @@ _pagebuf_lookup_pages( __FUNCTION__, gfp_mask); XFS_STATS_INC(pb_page_retries); - pagebuf_daemon_wakeup(0, gfp_mask); + xfsbufd_wakeup(0, gfp_mask); blk_congestion_wait(WRITE, HZ/50); goto retry; } @@ -1136,8 +1137,8 @@ pagebuf_iodone( if ((pb->pb_iodone) || (pb->pb_flags & PBF_ASYNC)) { if (schedule) { INIT_WORK(&pb->pb_iodone_work, pagebuf_iodone_work, pb); - queue_work(dataio ? pagebuf_dataio_workqueue : - pagebuf_logio_workqueue, &pb->pb_iodone_work); + queue_work(dataio ? xfsdatad_workqueue : + xfslogd_workqueue, &pb->pb_iodone_work); } else { pagebuf_iodone_work(pb); } @@ -1742,27 +1743,27 @@ pagebuf_runall_queues( } /* Defines for pagebuf daemon */ -STATIC DECLARE_COMPLETION(pagebuf_daemon_done); -STATIC struct task_struct *pagebuf_daemon_task; -STATIC int pagebuf_daemon_active; -STATIC int force_flush; -STATIC int force_sleep; +STATIC DECLARE_COMPLETION(xfsbufd_done); +STATIC struct task_struct *xfsbufd_task; +STATIC int xfsbufd_active; +STATIC int xfsbufd_force_flush; +STATIC int xfsbufd_force_sleep; STATIC int -pagebuf_daemon_wakeup( +xfsbufd_wakeup( int priority, unsigned int mask) { - if (force_sleep) + if (xfsbufd_force_sleep) return 0; - force_flush = 1; + xfsbufd_force_flush = 1; barrier(); - wake_up_process(pagebuf_daemon_task); + wake_up_process(xfsbufd_task); return 0; } STATIC int -pagebuf_daemon( +xfsbufd( void *data) { struct list_head tmp; @@ -1774,17 +1775,17 @@ pagebuf_daemon( daemonize("xfsbufd"); current->flags |= PF_MEMALLOC; - pagebuf_daemon_task = current; - pagebuf_daemon_active = 1; + xfsbufd_task = current; + xfsbufd_active = 1; barrier(); INIT_LIST_HEAD(&tmp); do { if (unlikely(current->flags & PF_FREEZE)) { - force_sleep = 1; + xfsbufd_force_sleep = 1; refrigerator(PF_FREEZE); } else { - force_sleep = 0; + xfsbufd_force_sleep = 0; } set_current_state(TASK_INTERRUPTIBLE); @@ -1797,7 +1798,7 @@ pagebuf_daemon( ASSERT(pb->pb_flags & PBF_DELWRI); if (!pagebuf_ispin(pb) && !pagebuf_cond_lock(pb)) { - if (!force_flush && + if (!xfsbufd_force_flush && time_before(jiffies, pb->pb_queuetime + age)) { pagebuf_unlock(pb); @@ -1824,10 +1825,10 @@ pagebuf_daemon( if (as_list_len > 0) purge_addresses(); - force_flush = 0; - } while (pagebuf_daemon_active); + xfsbufd_force_flush = 0; + } while (xfsbufd_active); - complete_and_exit(&pagebuf_daemon_done, 0); + complete_and_exit(&xfsbufd_done, 0); } /* @@ -1844,8 +1845,8 @@ xfs_flush_buftarg( xfs_buf_t *pb, *n; int pincount = 0; - pagebuf_runall_queues(pagebuf_dataio_workqueue); - pagebuf_runall_queues(pagebuf_logio_workqueue); + pagebuf_runall_queues(xfsdatad_workqueue); + pagebuf_runall_queues(xfslogd_workqueue); INIT_LIST_HEAD(&tmp); spin_lock(&pbd_delwrite_lock); @@ -1898,43 +1899,43 @@ xfs_flush_buftarg( } STATIC int -pagebuf_daemon_start(void) +xfs_buf_daemons_start(void) { - int rval; + int error = -ENOMEM; - pagebuf_logio_workqueue = create_workqueue("xfslogd"); - if (!pagebuf_logio_workqueue) - return -ENOMEM; + xfslogd_workqueue = create_workqueue("xfslogd"); + if (!xfslogd_workqueue) + goto out; - pagebuf_dataio_workqueue = create_workqueue("xfsdatad"); - if (!pagebuf_dataio_workqueue) { - destroy_workqueue(pagebuf_logio_workqueue); - return -ENOMEM; - } + xfsdatad_workqueue = create_workqueue("xfsdatad"); + if (!xfsdatad_workqueue) + goto out_destroy_xfslogd_workqueue; - rval = kernel_thread(pagebuf_daemon, NULL, CLONE_FS|CLONE_FILES); - if (rval < 0) { - destroy_workqueue(pagebuf_logio_workqueue); - destroy_workqueue(pagebuf_dataio_workqueue); - } + error = kernel_thread(xfsbufd, NULL, CLONE_FS|CLONE_FILES); + if (error < 0) + goto out_destroy_xfsdatad_workqueue; + return 0; - return rval; + out_destroy_xfsdatad_workqueue: + destroy_workqueue(xfsdatad_workqueue); + out_destroy_xfslogd_workqueue: + destroy_workqueue(xfslogd_workqueue); + out: + return error; } /* - * pagebuf_daemon_stop - * * Note: do not mark as __exit, it is called from pagebuf_terminate. */ STATIC void -pagebuf_daemon_stop(void) +xfs_buf_daemons_stop(void) { - pagebuf_daemon_active = 0; + xfsbufd_active = 0; barrier(); - wait_for_completion(&pagebuf_daemon_done); + wait_for_completion(&xfsbufd_done); - destroy_workqueue(pagebuf_logio_workqueue); - destroy_workqueue(pagebuf_dataio_workqueue); + destroy_workqueue(xfslogd_workqueue); + destroy_workqueue(xfsdatad_workqueue); } /* @@ -1944,27 +1945,37 @@ pagebuf_daemon_stop(void) int __init pagebuf_init(void) { - pagebuf_cache = kmem_cache_create("xfs_buf_t", sizeof(xfs_buf_t), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); - if (pagebuf_cache == NULL) { - printk("XFS: couldn't init xfs_buf_t cache\n"); - pagebuf_terminate(); - return -ENOMEM; - } + int error = -ENOMEM; + + pagebuf_zone = kmem_zone_init(sizeof(xfs_buf_t), "xfs_buf"); + if (!pagebuf_zone) + goto out; #ifdef PAGEBUF_TRACE pagebuf_trace_buf = ktrace_alloc(PAGEBUF_TRACE_SIZE, KM_SLEEP); #endif - pagebuf_daemon_start(); + error = xfs_buf_daemons_start(); + if (!error) + goto out_free_buf_zone; - pagebuf_shake = kmem_shake_register(pagebuf_daemon_wakeup); - if (pagebuf_shake == NULL) { - pagebuf_terminate(); - return -ENOMEM; + pagebuf_shake = kmem_shake_register(xfsbufd_wakeup); + if (!pagebuf_shake) { + error = -ENOMEM; + goto out_stop_daemons; } return 0; + + out_stop_daemons: + xfs_buf_daemons_stop(); + out_free_buf_zone: +#ifdef PAGEBUF_TRACE + ktrace_free(pagebuf_trace_buf); +#endif + kmem_zone_destroy(pagebuf_zone); + out: + return error; } @@ -1976,12 +1987,12 @@ pagebuf_init(void) void pagebuf_terminate(void) { - pagebuf_daemon_stop(); + xfs_buf_daemons_stop(); #ifdef PAGEBUF_TRACE ktrace_free(pagebuf_trace_buf); #endif - kmem_zone_destroy(pagebuf_cache); + kmem_zone_destroy(pagebuf_zone); kmem_shake_deregister(pagebuf_shake); } -- cgit v0.10.2 From 02de1f0abfc60aa4fead65eee4118d05667c93c3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:33:48 +1000 Subject: [XFS] fix some more compiler warnings in the vnode tracing code SGI-PV: 934679 SGI-Modid: xfs-linux:xfs-kern:192570a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index a832d16..250cad5 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c @@ -411,13 +411,13 @@ vn_remove( /* 0 */ (void *)(__psint_t)(vk), \ /* 1 */ (void *)(s), \ /* 2 */ (void *)(__psint_t) line, \ -/* 3 */ (void *)(vn_count(vp)), \ +/* 3 */ (void *)(__psint_t)(vn_count(vp)), \ /* 4 */ (void *)(ra), \ /* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \ /* 6 */ (void *)(__psint_t)current_cpu(), \ /* 7 */ (void *)(__psint_t)current_pid(), \ /* 8 */ (void *)__return_address, \ -/* 9 */ 0, 0, 0, 0, 0, 0, 0) +/* 9 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL) /* * Vnode tracing code. -- cgit v0.10.2 From cf9937c6c6c7edb6650411d1cf3cb57f072b1277 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:35:24 +1000 Subject: [XFS] Fix pagebuf slab initialization SGI-PV: 908809 SGI-Modid: xfs-linux:xfs-kern:192756a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index f5676ed..049f871 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1956,7 +1956,7 @@ pagebuf_init(void) #endif error = xfs_buf_daemons_start(); - if (!error) + if (error) goto out_free_buf_zone; pagebuf_shake = kmem_shake_register(xfsbufd_wakeup); -- cgit v0.10.2 From 4372d6e10349d4e8b012588f86f15c740c73a7c4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:36:00 +1000 Subject: [XFS] Remove dead code. Patch from Adrian Bunk SGI-PV: 936255 SGI-Modid: xfs-linux:xfs-kern:192759a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index 740d20d..c961ef7 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -371,68 +371,6 @@ xfs_qm_adjust_dqtimers( } /* - * Increment or reset warnings of a given dquot. - */ -int -xfs_qm_dqwarn( - xfs_disk_dquot_t *d, - uint flags) -{ - int warned; - - /* - * root's limits are not real limits. - */ - if (!d->d_id) - return (0); - - warned = 0; - if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) && - (INT_GET(d->d_bcount, ARCH_CONVERT) >= - INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) { - if (flags & XFS_QMOPT_DOWARN) { - INT_MOD(d->d_bwarns, ARCH_CONVERT, +1); - warned++; - } - } else { - if (!d->d_blk_softlimit || - (INT_GET(d->d_bcount, ARCH_CONVERT) < - INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) { - d->d_bwarns = 0; - } - } - - if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 && - (INT_GET(d->d_icount, ARCH_CONVERT) >= - INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) { - if (flags & XFS_QMOPT_DOWARN) { - INT_MOD(d->d_iwarns, ARCH_CONVERT, +1); - warned++; - } - } else { - if (!d->d_ino_softlimit || - (INT_GET(d->d_icount, ARCH_CONVERT) < - INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) { - d->d_iwarns = 0; - } - } -#ifdef QUOTADEBUG - if (INT_GET(d->d_iwarns, ARCH_CONVERT)) - cmn_err(CE_DEBUG, - "--------@@Inode warnings running : %Lu >= %Lu", - INT_GET(d->d_icount, ARCH_CONVERT), - INT_GET(d->d_ino_softlimit, ARCH_CONVERT)); - if (INT_GET(d->d_bwarns, ARCH_CONVERT)) - cmn_err(CE_DEBUG, - "--------@@Blks warnings running : %Lu >= %Lu", - INT_GET(d->d_bcount, ARCH_CONVERT), - INT_GET(d->d_blk_softlimit, ARCH_CONVERT)); -#endif - return (warned); -} - - -/* * initialize a buffer full of dquots and log the whole thing */ STATIC void diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h index 0c3fe31..35aeeaf 100644 --- a/fs/xfs/quota/xfs_dquot.h +++ b/fs/xfs/quota/xfs_dquot.h @@ -211,7 +211,6 @@ extern void xfs_qm_adjust_dqtimers(xfs_mount_t *, xfs_disk_dquot_t *); extern void xfs_qm_adjust_dqlimits(xfs_mount_t *, xfs_disk_dquot_t *); -extern int xfs_qm_dqwarn(xfs_disk_dquot_t *, uint); extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *, xfs_dqid_t, uint, uint, xfs_dquot_t **); extern void xfs_qm_dqput(xfs_dquot_t *); diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 163305a..09c4135 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c @@ -2331,20 +2331,6 @@ xfs_bmbt_lookup_ge( return xfs_bmbt_lookup(cur, XFS_LOOKUP_GE, stat); } -int /* error */ -xfs_bmbt_lookup_le( - xfs_btree_cur_t *cur, - xfs_fileoff_t off, - xfs_fsblock_t bno, - xfs_filblks_t len, - int *stat) /* success/failure */ -{ - cur->bc_rec.b.br_startoff = off; - cur->bc_rec.b.br_startblock = bno; - cur->bc_rec.b.br_blockcount = len; - return xfs_bmbt_lookup(cur, XFS_LOOKUP_LE, stat); -} - /* * Give the bmap btree a new root block. Copy the old broot contents * down into a real block and make the broot point to it. diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index 843ff12..0a40cf1 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h @@ -580,14 +580,6 @@ xfs_bmbt_lookup_ge( xfs_filblks_t, int *); -int -xfs_bmbt_lookup_le( - struct xfs_btree_cur *, - xfs_fileoff_t, - xfs_fsblock_t, - xfs_filblks_t, - int *); - /* * Give the bmap btree a new root block. Copy the old broot contents * down into a real block and make the broot point to it. diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 2121305..ca535d6 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -559,32 +559,6 @@ xfs_reserve_blocks( return(0); } -void -xfs_fs_log_dummy(xfs_mount_t *mp) -{ - xfs_trans_t *tp; - xfs_inode_t *ip; - - - tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); - atomic_inc(&mp->m_active_trans); - if (xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0)) { - xfs_trans_cancel(tp, 0); - return; - } - - ip = mp->m_rootip; - xfs_ilock(ip, XFS_ILOCK_EXCL); - - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - xfs_trans_ihold(tp, ip); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - xfs_trans_set_sync(tp); - xfs_trans_commit(tp, 0, NULL); - - xfs_iunlock(ip, XFS_ILOCK_EXCL); -} - int xfs_fs_goingdown( xfs_mount_t *mp, diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index bc8c8c7..e8274d6 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -146,51 +146,6 @@ xfs_inobp_check( #endif /* - * called from bwrite on xfs inode buffers - */ -void -xfs_inobp_bwcheck(xfs_buf_t *bp) -{ - xfs_mount_t *mp; - int i; - int j; - xfs_dinode_t *dip; - - ASSERT(XFS_BUF_FSPRIVATE3(bp, void *) != NULL); - - mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *); - - - j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; - - for (i = 0; i < j; i++) { - dip = (xfs_dinode_t *) xfs_buf_offset(bp, - i * mp->m_sb.sb_inodesize); - if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { - cmn_err(CE_WARN, -"Bad magic # 0x%x in XFS inode buffer 0x%Lx, starting blockno %Ld, offset 0x%x", - INT_GET(dip->di_core.di_magic, ARCH_CONVERT), - (__uint64_t)(__psunsigned_t) bp, - (__int64_t) XFS_BUF_ADDR(bp), - xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); - xfs_fs_cmn_err(CE_WARN, mp, - "corrupt, unmount and run xfs_repair"); - } - if (!dip->di_next_unlinked) { - cmn_err(CE_WARN, -"Bad next_unlinked field (0) in XFS inode buffer 0x%p, starting blockno %Ld, offset 0x%x", - (__uint64_t)(__psunsigned_t) bp, - (__int64_t) XFS_BUF_ADDR(bp), - xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); - xfs_fs_cmn_err(CE_WARN, mp, - "corrupt, unmount and run xfs_repair"); - } - } - - return; -} - -/* * This routine is called to map an inode number within a file * system to the buffer containing the on-disk version of the * inode. It returns a pointer to the buffer containing the diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index cb13f9a..23b48ac 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c @@ -234,9 +234,6 @@ xfs_lock_for_rename( return 0; } - -int rename_which_error_return = 0; - /* * xfs_rename */ @@ -316,7 +313,6 @@ xfs_rename( &num_inodes); if (error) { - rename_which_error_return = __LINE__; /* * We have nothing locked, no inode references, and * no transaction, so just get out. @@ -332,7 +328,6 @@ xfs_rename( */ if (target_ip == NULL && (src_dp != target_dp) && target_dp->i_d.di_nlink >= XFS_MAXLINK) { - rename_which_error_return = __LINE__; error = XFS_ERROR(EMLINK); xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); goto rele_return; @@ -359,7 +354,6 @@ xfs_rename( XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); } if (error) { - rename_which_error_return = __LINE__; xfs_trans_cancel(tp, 0); goto rele_return; } @@ -369,7 +363,6 @@ xfs_rename( */ if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) { xfs_trans_cancel(tp, cancel_flags); - rename_which_error_return = __LINE__; goto rele_return; } @@ -413,7 +406,6 @@ xfs_rename( if (spaceres == 0 && (error = XFS_DIR_CANENTER(mp, tp, target_dp, target_name, target_namelen))) { - rename_which_error_return = __LINE__; goto error_return; } /* @@ -425,11 +417,9 @@ xfs_rename( target_namelen, src_ip->i_ino, &first_block, &free_list, spaceres); if (error == ENOSPC) { - rename_which_error_return = __LINE__; goto error_return; } if (error) { - rename_which_error_return = __LINE__; goto abort_return; } xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); @@ -437,7 +427,6 @@ xfs_rename( if (new_parent && src_is_directory) { error = xfs_bumplink(tp, target_dp); if (error) { - rename_which_error_return = __LINE__; goto abort_return; } } @@ -455,7 +444,6 @@ xfs_rename( if (!(XFS_DIR_ISEMPTY(target_ip->i_mount, target_ip)) || (target_ip->i_d.di_nlink > 2)) { error = XFS_ERROR(EEXIST); - rename_which_error_return = __LINE__; goto error_return; } } @@ -473,7 +461,6 @@ xfs_rename( target_namelen, src_ip->i_ino, &first_block, &free_list, spaceres); if (error) { - rename_which_error_return = __LINE__; goto abort_return; } xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); @@ -484,7 +471,6 @@ xfs_rename( */ error = xfs_droplink(tp, target_ip); if (error) { - rename_which_error_return = __LINE__; goto abort_return; } target_ip_dropped = 1; @@ -495,7 +481,6 @@ xfs_rename( */ error = xfs_droplink(tp, target_ip); if (error) { - rename_which_error_return = __LINE__; goto abort_return; } } @@ -519,7 +504,6 @@ xfs_rename( &free_list, spaceres); ASSERT(error != EEXIST); if (error) { - rename_which_error_return = __LINE__; goto abort_return; } xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); @@ -550,7 +534,6 @@ xfs_rename( */ error = xfs_droplink(tp, src_dp); if (error) { - rename_which_error_return = __LINE__; goto abort_return; } } @@ -558,7 +541,6 @@ xfs_rename( error = XFS_DIR_REMOVENAME(mp, tp, src_dp, src_name, src_namelen, src_ip->i_ino, &first_block, &free_list, spaceres); if (error) { - rename_which_error_return = __LINE__; goto abort_return; } xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 3db0e22..a865f60 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -332,25 +332,6 @@ undo_blocks: /* - * This is called to set the a callback to be called when the given - * transaction is committed to disk. The transaction pointer and the - * argument pointer will be passed to the callback routine. - * - * Only one callback can be associated with any single transaction. - */ -void -xfs_trans_callback( - xfs_trans_t *tp, - xfs_trans_callback_t callback, - void *arg) -{ - ASSERT(tp->t_callback == NULL); - tp->t_callback = callback; - tp->t_callarg = arg; -} - - -/* * Record the indicated change to the given field for application * to the file system's superblock when the transaction commits. * For now, just store the change in the transaction structure. diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index bd37ccb..ec541d6 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -987,8 +987,6 @@ xfs_trans_t *_xfs_trans_alloc(struct xfs_mount *, uint); xfs_trans_t *xfs_trans_dup(xfs_trans_t *); int xfs_trans_reserve(xfs_trans_t *, uint, uint, uint, uint, uint); -void xfs_trans_callback(xfs_trans_t *, - void (*)(xfs_trans_t *, void *), void *); void xfs_trans_mod_sb(xfs_trans_t *, uint, long); struct xfs_buf *xfs_trans_get_buf(xfs_trans_t *, struct xfs_buftarg *, xfs_daddr_t, int, uint); @@ -1010,7 +1008,6 @@ int xfs_trans_iget(struct xfs_mount *, xfs_trans_t *, xfs_ino_t , uint, uint, struct xfs_inode **); void xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint); void xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *); -void xfs_trans_ihold_release(xfs_trans_t *, struct xfs_inode *); void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint); diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c index e2c3706f..7e7631c 100644 --- a/fs/xfs/xfs_trans_inode.c +++ b/fs/xfs/xfs_trans_inode.c @@ -253,24 +253,6 @@ xfs_trans_ihold( ip->i_itemp->ili_flags |= XFS_ILI_HOLD; } -/* - * Cancel the previous inode hold request made on this inode - * for this transaction. - */ -/*ARGSUSED*/ -void -xfs_trans_ihold_release( - xfs_trans_t *tp, - xfs_inode_t *ip) -{ - ASSERT(ip->i_transp == tp); - ASSERT(ip->i_itemp != NULL); - ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); - ASSERT(ip->i_itemp->ili_flags & XFS_ILI_HOLD); - - ip->i_itemp->ili_flags &= ~XFS_ILI_HOLD; -} - /* * This is called to mark the fields indicated in fieldmask as needing -- cgit v0.10.2 From ba0f32d46049e2b625dabd33c7964f8ca2cd7651 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:36:52 +1000 Subject: [XFS] mark various symbols static Patch from Adrian Bunk SGI-PV: 936255 SGI-Modid: xfs-linux:xfs-kern:192760a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index c961ef7..9ce4714 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -101,7 +101,7 @@ int xfs_dqerror_mod = 33; * is the d_id field. The idea is to fill in the entire q_core * when we read in the on disk dquot. */ -xfs_dquot_t * +STATIC xfs_dquot_t * xfs_qm_dqinit( xfs_mount_t *mp, xfs_dqid_t id, diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index a5425ee..f5271b7 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c @@ -428,7 +428,7 @@ xfs_qm_dquot_logitem_committing( /* * This is the ops vector for dquots */ -struct xfs_item_ops xfs_dquot_item_ops = { +STATIC struct xfs_item_ops xfs_dquot_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_qm_dquot_logitem_format, @@ -646,7 +646,7 @@ xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn) return; } -struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { +STATIC struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_qm_qoff_logitem_format, @@ -669,7 +669,7 @@ struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { /* * This is the ops vector shared by all quotaoff-start log items. */ -struct xfs_item_ops xfs_qm_qoff_logitem_ops = { +STATIC struct xfs_item_ops xfs_qm_qoff_logitem_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_qm_qoff_logitem_format, diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 89f2cd6..41bbc49 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -81,12 +81,18 @@ struct xfs_qm *xfs_Gqm; kmem_zone_t *qm_dqzone; kmem_zone_t *qm_dqtrxzone; -kmem_shaker_t xfs_qm_shaker; +STATIC kmem_shaker_t xfs_qm_shaker; STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int); STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); +STATIC void xfs_qm_freelist_init(xfs_frlist_t *); +STATIC void xfs_qm_freelist_destroy(xfs_frlist_t *); +STATIC int xfs_qm_mplist_nowait(xfs_mount_t *); +STATIC int xfs_qm_dqhashlock_nowait(xfs_dquot_t *); + STATIC int xfs_qm_init_quotainos(xfs_mount_t *); +STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); STATIC int xfs_qm_shake(int, unsigned int); #ifdef DEBUG @@ -184,7 +190,7 @@ xfs_Gqm_init(void) /* * Destroy the global quota manager when its reference count goes to zero. */ -void +STATIC void xfs_qm_destroy( struct xfs_qm *xqm) { @@ -509,7 +515,7 @@ out: * Flush all dquots of the given file system to disk. The dquots are * _not_ purged from memory here, just their data written to disk. */ -int +STATIC int xfs_qm_dqflush_all( xfs_mount_t *mp, int flags) @@ -1149,7 +1155,7 @@ xfs_qm_sync( * This initializes all the quota information that's kept in the * mount structure */ -int +STATIC int xfs_qm_init_quotainfo( xfs_mount_t *mp) { @@ -2751,7 +2757,7 @@ xfs_qm_vop_dqattach_and_dqmod_newinode( } /* ------------- list stuff -----------------*/ -void +STATIC void xfs_qm_freelist_init(xfs_frlist_t *ql) { ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql; @@ -2760,7 +2766,7 @@ xfs_qm_freelist_init(xfs_frlist_t *ql) ql->qh_nelems = 0; } -void +STATIC void xfs_qm_freelist_destroy(xfs_frlist_t *ql) { xfs_dquot_t *dqp, *nextdqp; @@ -2786,7 +2792,7 @@ xfs_qm_freelist_destroy(xfs_frlist_t *ql) ASSERT(ql->qh_nelems == 0); } -void +STATIC void xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq) { dq->dq_flnext = ql->qh_next; @@ -2816,7 +2822,7 @@ xfs_qm_freelist_append(xfs_frlist_t *ql, xfs_dquot_t *dq) xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq); } -int +STATIC int xfs_qm_dqhashlock_nowait( xfs_dquot_t *dqp) { @@ -2836,7 +2842,7 @@ xfs_qm_freelist_lock_nowait( return (locked); } -int +STATIC int xfs_qm_mplist_nowait( xfs_mount_t *mp) { diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h index dcf1a7a..ae626ec 100644 --- a/fs/xfs/quota/xfs_qm.h +++ b/fs/xfs/quota/xfs_qm.h @@ -184,7 +184,6 @@ typedef struct xfs_dquot_acct { extern void xfs_mount_reset_sbqflags(xfs_mount_t *); -extern int xfs_qm_init_quotainfo(xfs_mount_t *); extern void xfs_qm_destroy_quotainfo(xfs_mount_t *); extern int xfs_qm_mount_quotas(xfs_mount_t *, int); extern void xfs_qm_mount_quotainit(xfs_mount_t *, uint); @@ -215,14 +214,9 @@ extern int xfs_qm_vop_chown_reserve(xfs_trans_t *, xfs_inode_t *, xfs_dquot_t *, xfs_dquot_t *, uint); /* list stuff */ -extern void xfs_qm_freelist_init(xfs_frlist_t *); -extern void xfs_qm_freelist_destroy(xfs_frlist_t *); -extern void xfs_qm_freelist_insert(xfs_frlist_t *, xfs_dquot_t *); extern void xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *); extern void xfs_qm_freelist_unlink(xfs_dquot_t *); extern int xfs_qm_freelist_lock_nowait(xfs_qm_t *); -extern int xfs_qm_mplist_nowait(xfs_mount_t *); -extern int xfs_qm_dqhashlock_nowait(xfs_dquot_t *); /* system call interface */ extern int xfs_qm_quotactl(bhv_desc_t *, int, int, xfs_caddr_t); diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c index be67d9c..09b1171 100644 --- a/fs/xfs/quota/xfs_qm_bhv.c +++ b/fs/xfs/quota/xfs_qm_bhv.c @@ -359,7 +359,7 @@ xfs_qm_dqrele_null( } -struct xfs_qmops xfs_qmcore_xfs = { +STATIC struct xfs_qmops xfs_qmcore_xfs = { .xfs_qminit = xfs_qm_newmount, .xfs_qmdone = xfs_qm_unmount_quotadestroy, .xfs_qmmount = xfs_qm_endmount, diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c index 149b2a1..3644ca0 100644 --- a/fs/xfs/quota/xfs_trans_dquot.c +++ b/fs/xfs/quota/xfs_trans_dquot.c @@ -187,7 +187,7 @@ xfs_trans_dup_dqinfo( /* * Wrap around mod_dquot to account for both user and group quotas. */ -void +STATIC void xfs_trans_mod_dquot_byino( xfs_trans_t *tp, xfs_inode_t *ip, @@ -368,7 +368,7 @@ xfs_trans_dqlockedjoin( * Unreserve just the reservations done by this transaction. * dquot is still left locked at exit. */ -void +STATIC void xfs_trans_apply_dquot_deltas( xfs_trans_t *tp) { diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 36603db..dcfe197 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -59,7 +59,7 @@ #define XFSA_FIXUP_BNO_OK 1 #define XFSA_FIXUP_CNT_OK 2 -int +STATIC int xfs_alloc_search_busy(xfs_trans_t *tp, xfs_agnumber_t agno, xfs_agblock_t bno, @@ -2562,7 +2562,7 @@ xfs_alloc_clear_busy(xfs_trans_t *tp, /* * returns non-zero if any of (agno,bno):len is in a busy list */ -int +STATIC int xfs_alloc_search_busy(xfs_trans_t *tp, xfs_agnumber_t agno, xfs_agblock_t bno, diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index ee8b590..a41ad3a 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -71,6 +71,11 @@ * Provide the external interfaces to manage attribute lists. */ +#define ATTR_SYSCOUNT 2 +STATIC struct attrnames posix_acl_access; +STATIC struct attrnames posix_acl_default; +STATIC struct attrnames *attr_system_names[ATTR_SYSCOUNT]; + /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ @@ -83,6 +88,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); /* * Internal routines when attribute list is one block. */ +STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); @@ -90,6 +96,7 @@ STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); /* * Internal routines when attribute list is more than one block. */ +STATIC int xfs_attr_node_get(xfs_da_args_t *args); STATIC int xfs_attr_node_addname(xfs_da_args_t *args); STATIC int xfs_attr_node_removename(xfs_da_args_t *args); STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context); @@ -1102,7 +1109,7 @@ xfs_attr_leaf_removename(xfs_da_args_t *args) * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */ -int +STATIC int xfs_attr_leaf_get(xfs_da_args_t *args) { xfs_dabuf_t *bp; @@ -1707,7 +1714,7 @@ xfs_attr_refillstate(xfs_da_state_t *state) * block, ie: both true Btree attr lists and for single-leaf-blocks with * "remote" values taking up more blocks. */ -int +STATIC int xfs_attr_node_get(xfs_da_args_t *args) { xfs_da_state_t *state; @@ -2398,7 +2405,7 @@ posix_acl_default_exists( return xfs_acl_vhasacl_default(vp); } -struct attrnames posix_acl_access = { +STATIC struct attrnames posix_acl_access = { .attr_name = "posix_acl_access", .attr_namelen = sizeof("posix_acl_access") - 1, .attr_get = posix_acl_access_get, @@ -2407,7 +2414,7 @@ struct attrnames posix_acl_access = { .attr_exists = posix_acl_access_exists, }; -struct attrnames posix_acl_default = { +STATIC struct attrnames posix_acl_default = { .attr_name = "posix_acl_default", .attr_namelen = sizeof("posix_acl_default") - 1, .attr_get = posix_acl_default_get, @@ -2416,7 +2423,7 @@ struct attrnames posix_acl_default = { .attr_exists = posix_acl_default_exists, }; -struct attrnames *attr_system_names[] = +STATIC struct attrnames *attr_system_names[] = { &posix_acl_access, &posix_acl_default }; diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h index 67cd0f5..45ab1c5 100644 --- a/fs/xfs/xfs_attr.h +++ b/fs/xfs/xfs_attr.h @@ -76,11 +76,6 @@ extern struct attrnames attr_system; extern struct attrnames attr_trusted; extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT]; -#define ATTR_SYSCOUNT 2 -extern struct attrnames posix_acl_access; -extern struct attrnames posix_acl_default; -extern struct attrnames *attr_system_names[ATTR_SYSCOUNT]; - extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int); extern int attr_generic_list(struct vnode *, void *, size_t, int, ssize_t *); @@ -184,8 +179,6 @@ int xfs_attr_list(bhv_desc_t *, char *, int, int, struct attrlist_cursor_kern *, struct cred *); int xfs_attr_inactive(struct xfs_inode *dp); -int xfs_attr_node_get(struct xfs_da_args *); -int xfs_attr_leaf_get(struct xfs_da_args *); int xfs_attr_shortform_getvalue(struct xfs_da_args *); int xfs_attr_fetch(struct xfs_inode *, char *, int, char *, int *, int, struct cred *); diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index b11256e..1cdd574 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -79,6 +79,8 @@ /* * Routines used for growing the Btree. */ +STATIC int xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t which_block, + xfs_dabuf_t **bpp); STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args, int freemap_index); STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer); @@ -92,6 +94,16 @@ STATIC int xfs_attr_leaf_figure_balance(xfs_da_state_t *state, int *number_usedbytes_in_blk1); /* + * Routines used for shrinking the Btree. + */ +STATIC int xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, + xfs_dabuf_t *bp, int level); +STATIC int xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, + xfs_dabuf_t *bp); +STATIC int xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, + xfs_dablk_t blkno, int blkcnt); + +/* * Utility routines. */ STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf, @@ -99,6 +111,10 @@ STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf, xfs_attr_leafblock_t *dst_leaf, int dst_start, int move_count, xfs_mount_t *mp); +STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); +STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context, + attrnames_t *, char *name, int namelen, + int valuelen); /*======================================================================== @@ -774,7 +790,7 @@ out: * Create the initial contents of a leaf attribute list * or a leaf in a node attribute list. */ -int +STATIC int xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) { xfs_attr_leafblock_t *leaf; @@ -2209,7 +2225,7 @@ xfs_attr_leaf_lasthash(xfs_dabuf_t *bp, int *count) * Calculate the number of bytes used to store the indicated attribute * (whether local or remote only calculate bytes in this block). */ -int +STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index) { xfs_attr_leaf_name_local_t *name_loc; @@ -2380,7 +2396,7 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) * we may be reading them directly out of a user buffer. */ /*ARGSUSED*/ -int +STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp, char *name, int namelen, int valuelen) { @@ -2740,7 +2756,7 @@ xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp) * Recurse (gasp!) through the attribute nodes until we find leaves. * We're doing a depth-first traversal in order to invalidate everything. */ -int +STATIC int xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp, int level) { @@ -2849,7 +2865,7 @@ xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp, * Note that we must release the lock on the buffer so that we are not * caught holding something that the logging code wants to flush to disk. */ -int +STATIC int xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp) { xfs_attr_leafblock_t *leaf; @@ -2934,7 +2950,7 @@ xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp) * Look at all the extents for this logical region, * invalidate any buffers that are incore/in transactions. */ -int +STATIC int xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dablk_t blkno, int blkcnt) { diff --git a/fs/xfs/xfs_attr_leaf.h b/fs/xfs/xfs_attr_leaf.h index b1480e0..0a4cfad 100644 --- a/fs/xfs/xfs_attr_leaf.h +++ b/fs/xfs/xfs_attr_leaf.h @@ -261,8 +261,6 @@ int xfs_attr_leaf_flipflags(xfs_da_args_t *args); /* * Routines used for growing the Btree. */ -int xfs_attr_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, - struct xfs_dabuf **bpp); int xfs_attr_leaf_split(struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk); @@ -284,12 +282,6 @@ void xfs_attr_leaf_unbalance(struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk); int xfs_attr_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp); -int xfs_attr_node_inactive(struct xfs_trans **trans, struct xfs_inode *dp, - struct xfs_dabuf *bp, int level); -int xfs_attr_leaf_inactive(struct xfs_trans **trans, struct xfs_inode *dp, - struct xfs_dabuf *bp); -int xfs_attr_leaf_freextent(struct xfs_trans **trans, struct xfs_inode *dp, - xfs_dablk_t blkno, int blkcnt); /* * Utility routines. @@ -299,10 +291,6 @@ int xfs_attr_leaf_order(struct xfs_dabuf *leaf1_bp, struct xfs_dabuf *leaf2_bp); int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int blocksize, int *local); -int xfs_attr_leaf_entsize(struct xfs_attr_leafblock *leaf, int index); -int xfs_attr_put_listent(struct xfs_attr_list_context *context, - struct attrnames *, char *name, int namelen, - int valuelen); int xfs_attr_rolltrans(struct xfs_trans **transp, struct xfs_inode *dp); #endif /* __XFS_ATTR_LEAF_H__ */ diff --git a/fs/xfs/xfs_bit.c b/fs/xfs/xfs_bit.c index a20a6c3..76c9ad3 100644 --- a/fs/xfs/xfs_bit.c +++ b/fs/xfs/xfs_bit.c @@ -45,7 +45,7 @@ /* * Index of high bit number in byte, -1 for none set, 0..7 otherwise. */ -const char xfs_highbit[256] = { +STATIC const char xfs_highbit[256] = { -1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */ 3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */ 4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */ diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index de31624..f6f5ad3 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -301,6 +301,19 @@ xfs_bmap_search_extents( xfs_bmbt_irec_t *gotp, /* out: extent entry found */ xfs_bmbt_irec_t *prevp); /* out: previous extent entry found */ +/* + * Check the last inode extent to determine whether this allocation will result + * in blocks being allocated at the end of the file. When we allocate new data + * blocks at the end of the file which do not start at the previous data block, + * we will try to align the new blocks at stripe unit boundaries. + */ +STATIC int /* error */ +xfs_bmap_isaeof( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t off, /* file offset in fsblocks */ + int whichfork, /* data or attribute fork */ + char *aeof); /* return value */ + #ifdef XFS_BMAP_TRACE /* * Add a bmap trace buffer entry. Base routine for the others. @@ -5714,7 +5727,7 @@ unlock_and_return: * blocks at the end of the file which do not start at the previous data block, * we will try to align the new blocks at stripe unit boundaries. */ -int /* error */ +STATIC int /* error */ xfs_bmap_isaeof( xfs_inode_t *ip, /* incore inode pointer */ xfs_fileoff_t off, /* file offset in fsblocks */ diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index f1bc22f..e6d22ec 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h @@ -332,19 +332,6 @@ xfs_getbmap( int iflags); /* interface flags */ /* - * Check the last inode extent to determine whether this allocation will result - * in blocks being allocated at the end of the file. When we allocate new data - * blocks at the end of the file which do not start at the previous data block, - * we will try to align the new blocks at stripe unit boundaries. - */ -int -xfs_bmap_isaeof( - struct xfs_inode *ip, - xfs_fileoff_t off, - int whichfork, - char *aeof); - -/* * Check if the endoff is outside the last extent. If so the caller will grow * the allocation to a stripe unit boundary */ diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 9dd22dd..797f4d9 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c @@ -90,6 +90,16 @@ xfs_btree_maxrecs( */ /* + * Retrieve the block pointer from the cursor at the given level. + * This may be a bmap btree root or from a buffer. + */ +xfs_btree_block_t * /* generic btree block pointer */ +xfs_btree_get_block( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree */ + struct xfs_buf **bpp); /* buffer containing the block */ + +/* * Checking routine: return maxrecs for the block. */ STATIC int /* number of records fitting in block */ @@ -497,7 +507,7 @@ xfs_btree_firstrec( * Retrieve the block pointer from the cursor at the given level. * This may be a bmap btree root or from a buffer. */ -xfs_btree_block_t * /* generic btree block pointer */ +STATIC xfs_btree_block_t * /* generic btree block pointer */ xfs_btree_get_block( xfs_btree_cur_t *cur, /* btree cursor */ int level, /* level in btree */ diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index 93872bb..09b4e15 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h @@ -325,16 +325,6 @@ xfs_btree_firstrec( int level); /* level to change */ /* - * Retrieve the block pointer from the cursor at the given level. - * This may be a bmap btree root or from a buffer. - */ -xfs_btree_block_t * /* generic btree block pointer */ -xfs_btree_get_block( - xfs_btree_cur_t *cur, /* btree cursor */ - int level, /* level in btree */ - struct xfs_buf **bpp); /* buffer containing the block */ - -/* * Get a buffer for the block, return it with no data read. * Long-form addressing. */ diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 9ab0039..30b8285 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -172,7 +172,7 @@ STATIC void xfs_buf_do_callbacks(xfs_buf_t *bp, xfs_log_item_t *lip); * * If the XFS_BLI_STALE flag has been set, then log nothing. */ -uint +STATIC uint xfs_buf_item_size( xfs_buf_log_item_t *bip) { @@ -240,7 +240,7 @@ xfs_buf_item_size( * format structure, and the rest point to contiguous chunks * within the buffer. */ -void +STATIC void xfs_buf_item_format( xfs_buf_log_item_t *bip, xfs_log_iovec_t *log_vector) @@ -365,7 +365,7 @@ xfs_buf_item_format( * item in memory so it cannot be written out. Simply call bpin() * on the buffer to do this. */ -void +STATIC void xfs_buf_item_pin( xfs_buf_log_item_t *bip) { @@ -391,7 +391,7 @@ xfs_buf_item_pin( * If the XFS_BLI_STALE flag is set and we are the last reference, * then free up the buf log item and unlock the buffer. */ -void +STATIC void xfs_buf_item_unpin( xfs_buf_log_item_t *bip, int stale) @@ -446,7 +446,7 @@ xfs_buf_item_unpin( * so we need to free the item's descriptor (that points to the item) * in the transaction. */ -void +STATIC void xfs_buf_item_unpin_remove( xfs_buf_log_item_t *bip, xfs_trans_t *tp) @@ -493,7 +493,7 @@ xfs_buf_item_unpin_remove( * the lock right away, return 0. If we can get the lock, pull the * buffer from the free list, mark it busy, and return 1. */ -uint +STATIC uint xfs_buf_item_trylock( xfs_buf_log_item_t *bip) { @@ -537,7 +537,7 @@ xfs_buf_item_trylock( * This is for support of xfs_trans_bhold(). Make sure the * XFS_BLI_HOLD field is cleared if we don't free the item. */ -void +STATIC void xfs_buf_item_unlock( xfs_buf_log_item_t *bip) { @@ -635,7 +635,7 @@ xfs_buf_item_unlock( * by returning the original lsn of that transaction here rather than * the current one. */ -xfs_lsn_t +STATIC xfs_lsn_t xfs_buf_item_committed( xfs_buf_log_item_t *bip, xfs_lsn_t lsn) @@ -654,7 +654,7 @@ xfs_buf_item_committed( * and have aborted this transaction, we'll trap this buffer when it tries to * get written out. */ -void +STATIC void xfs_buf_item_abort( xfs_buf_log_item_t *bip) { @@ -674,7 +674,7 @@ xfs_buf_item_abort( * B_DELWRI set, then get it going out to disk with a call to bawrite(). * If not, then just release the buffer. */ -void +STATIC void xfs_buf_item_push( xfs_buf_log_item_t *bip) { @@ -693,7 +693,7 @@ xfs_buf_item_push( } /* ARGSUSED */ -void +STATIC void xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn) { } @@ -701,7 +701,7 @@ xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn) /* * This is the ops vector shared by all buf log items. */ -struct xfs_item_ops xfs_buf_item_ops = { +STATIC struct xfs_item_ops xfs_buf_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_buf_item_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_buf_item_format, diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index d7fe288..8b792dd 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c @@ -113,7 +113,10 @@ STATIC void xfs_da_node_unbalance(xfs_da_state_t *state, STATIC uint xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count); STATIC int xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp); STATIC xfs_dabuf_t *xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra); - +STATIC int xfs_da_blk_unlink(xfs_da_state_t *state, + xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk); +STATIC void xfs_da_state_kill_altpath(xfs_da_state_t *state); /*======================================================================== * Routines used for growing the Btree. @@ -1424,7 +1427,7 @@ xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count) /* * Unlink a block from a doubly linked list of blocks. */ -int /* error */ +STATIC int /* error */ xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, xfs_da_state_blk_t *save_blk) { @@ -2381,7 +2384,7 @@ xfs_da_state_alloc(void) /* * Kill the altpath contents of a da-state structure. */ -void +STATIC void xfs_da_state_kill_altpath(xfs_da_state_t *state) { int i; diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index 9fc699d..3a9b9e8 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h @@ -296,8 +296,6 @@ int xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, /* * Utility routines. */ -int xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, - xfs_da_state_blk_t *save_blk); int xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, xfs_da_state_blk_t *new_blk); @@ -320,7 +318,6 @@ uint xfs_da_hashname(uchar_t *name_string, int name_length); uint xfs_da_log2_roundup(uint i); xfs_da_state_t *xfs_da_state_alloc(void); void xfs_da_state_free(xfs_da_state_t *state); -void xfs_da_state_kill_altpath(xfs_da_state_t *state); void xfs_da_buf_done(xfs_dabuf_t *dabuf); void xfs_da_log_buf(struct xfs_trans *tp, xfs_dabuf_t *dabuf, uint first, diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c index db9887a..a0aa0e4 100644 --- a/fs/xfs/xfs_dir2_data.c +++ b/fs/xfs/xfs_dir2_data.c @@ -304,7 +304,7 @@ xfs_dir2_data_freeinsert( /* * Remove a bestfree entry from the table. */ -void +STATIC void xfs_dir2_data_freeremove( xfs_dir2_data_t *d, /* data block pointer */ xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */ diff --git a/fs/xfs/xfs_dir2_data.h b/fs/xfs/xfs_dir2_data.h index 3f02294..476cac9 100644 --- a/fs/xfs/xfs_dir2_data.h +++ b/fs/xfs/xfs_dir2_data.h @@ -193,10 +193,6 @@ extern xfs_dir2_data_free_t * xfs_dir2_data_unused_t *dup, int *loghead); extern void - xfs_dir2_data_freeremove(xfs_dir2_data_t *d, - xfs_dir2_data_free_t *dfp, int *loghead); - -extern void xfs_dir2_data_freescan(struct xfs_mount *mp, xfs_dir2_data_t *d, int *loghead, char *aendp); diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 262d1e8..79918df 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c @@ -77,6 +77,10 @@ static void xfs_dir2_leaf_check(xfs_inode_t *dp, xfs_dabuf_t *bp); #endif static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **lbpp, int *indexp, xfs_dabuf_t **dbpp); +static void xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, + int first, int last); +extern void xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp); + /* * Convert a block form directory to a leaf form directory. @@ -1214,7 +1218,7 @@ xfs_dir2_leaf_init( /* * Log the bests entries indicated from a leaf1 block. */ -void +static void xfs_dir2_leaf_log_bests( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp, /* leaf buffer */ @@ -1278,7 +1282,7 @@ xfs_dir2_leaf_log_header( /* * Log the tail of the leaf1 block. */ -void +STATIC void xfs_dir2_leaf_log_tail( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp) /* leaf buffer */ diff --git a/fs/xfs/xfs_dir2_leaf.h b/fs/xfs/xfs_dir2_leaf.h index 7f20eee..3303cd6 100644 --- a/fs/xfs/xfs_dir2_leaf.h +++ b/fs/xfs/xfs_dir2_leaf.h @@ -330,15 +330,8 @@ extern void int first, int last); extern void - xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, - int first, int last); - -extern void xfs_dir2_leaf_log_header(struct xfs_trans *tp, struct xfs_dabuf *bp); -extern void - xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp); - extern int xfs_dir2_leaf_lookup(struct xfs_da_args *args); diff --git a/fs/xfs/xfs_dir_leaf.c b/fs/xfs/xfs_dir_leaf.c index 617018d..c2ea617 100644 --- a/fs/xfs/xfs_dir_leaf.c +++ b/fs/xfs/xfs_dir_leaf.c @@ -91,6 +91,10 @@ STATIC int xfs_dir_leaf_figure_balance(xfs_da_state_t *state, int *number_entries_in_blk1, int *number_namebytes_in_blk1); +STATIC int xfs_dir_leaf_create(struct xfs_da_args *args, + xfs_dablk_t which_block, + struct xfs_dabuf **bpp); + /* * Utility routines. */ @@ -781,7 +785,7 @@ xfs_dir_leaf_to_node(xfs_da_args_t *args) * Create the initial contents of a leaf directory * or a leaf in a node directory. */ -int +STATIC int xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) { xfs_dir_leafblock_t *leaf; diff --git a/fs/xfs/xfs_dir_leaf.h b/fs/xfs/xfs_dir_leaf.h index 00d68d3..dd423ce 100644 --- a/fs/xfs/xfs_dir_leaf.h +++ b/fs/xfs/xfs_dir_leaf.h @@ -202,8 +202,6 @@ int xfs_dir_leaf_to_shortform(struct xfs_da_args *args); /* * Routines used for growing the Btree. */ -int xfs_dir_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, - struct xfs_dabuf **bpp); int xfs_dir_leaf_split(struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk); diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c index bbe1dea..dcd3fdd 100644 --- a/fs/xfs/xfs_error.c +++ b/fs/xfs/xfs_error.c @@ -280,7 +280,7 @@ xfs_error_report( } } -void +STATIC void xfs_hex_dump(void *p, int length) { __uint8_t *uip = (__uint8_t*)p; diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h index 6bc0535..52ee2b9 100644 --- a/fs/xfs/xfs_error.h +++ b/fs/xfs/xfs_error.h @@ -73,9 +73,6 @@ xfs_corruption_error( int linenum, inst_t *ra); -extern void -xfs_hex_dump(void *p, int length); - #define XFS_ERROR_REPORT(e, lvl, mp) \ xfs_error_report(e, lvl, mp, __FILE__, __LINE__, __return_address) #define XFS_CORRUPTION_ERROR(e, lvl, mp, mem) \ diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 5eafd5b..4b45ff7 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -288,7 +288,7 @@ xfs_efi_item_committing(xfs_efi_log_item_t *efip, xfs_lsn_t lsn) /* * This is the ops vector shared by all efi log items. */ -struct xfs_item_ops xfs_efi_item_ops = { +STATIC struct xfs_item_ops xfs_efi_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_efi_item_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_efi_item_format, @@ -615,7 +615,7 @@ xfs_efd_item_committing(xfs_efd_log_item_t *efip, xfs_lsn_t lsn) /* * This is the ops vector shared by all efd log items. */ -struct xfs_item_ops xfs_efd_item_ops = { +STATIC struct xfs_item_ops xfs_efd_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_efd_item_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_efd_item_format, diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index e8274d6..9942163 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -158,7 +158,7 @@ xfs_inobp_check( * Use xfs_imap() to determine the size and location of the * buffer to read from disk. */ -int +STATIC int xfs_inotobp( xfs_mount_t *mp, xfs_trans_t *tp, @@ -2111,7 +2111,7 @@ static __inline__ int xfs_inode_clean(xfs_inode_t *ip) (ip->i_update_core == 0)); } -void +STATIC void xfs_ifree_cluster( xfs_inode_t *free_ip, xfs_trans_t *tp, @@ -2830,7 +2830,7 @@ xfs_iunpin( * be subsequently pinned once someone is waiting for it to be * unpinned. */ -void +STATIC void xfs_iunpin_wait( xfs_inode_t *ip) { diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 37e1c31..2c9a7c4 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -487,8 +487,6 @@ int xfs_finish_reclaim_all(struct xfs_mount *, int); /* * xfs_inode.c prototypes. */ -int xfs_inotobp(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, - xfs_dinode_t **, struct xfs_buf **, int *); int xfs_itobp(struct xfs_mount *, struct xfs_trans *, xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **, xfs_daddr_t); diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 768cb18..0eed30f 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -910,7 +910,7 @@ xfs_inode_item_committing( /* * This is the ops vector shared by all buf log items. */ -struct xfs_item_ops xfs_inode_item_ops = { +STATIC struct xfs_item_ops xfs_inode_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_inode_item_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_inode_item_format, diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 092d5fb..1cd2ac1 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -134,7 +134,7 @@ STATIC void xlog_verify_tail_lsn(xlog_t *log, xlog_in_core_t *iclog, #define xlog_verify_tail_lsn(a,b,c) #endif -int xlog_iclogs_empty(xlog_t *log); +STATIC int xlog_iclogs_empty(xlog_t *log); #ifdef DEBUG int xlog_do_error = 0; @@ -1857,7 +1857,7 @@ xlog_write(xfs_mount_t * mp, * * State Change: DIRTY -> ACTIVE */ -void +STATIC void xlog_state_clean_log(xlog_t *log) { xlog_in_core_t *iclog; @@ -3542,7 +3542,7 @@ xfs_log_force_umount( return (retval); } -int +STATIC int xlog_iclogs_empty(xlog_t *log) { xlog_in_core_t *iclog; diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index c31e3ce..1a1d452 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h @@ -535,7 +535,6 @@ typedef struct log { /* common routines */ extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp); -extern int xlog_find_head(xlog_t *log, xfs_daddr_t *head_blk); extern int xlog_find_tail(xlog_t *log, xfs_daddr_t *head_blk, xfs_daddr_t *tail_blk, @@ -548,7 +547,6 @@ extern void xlog_recover_process_iunlinks(xlog_t *log); extern struct xfs_buf *xlog_get_bp(xlog_t *, int); extern void xlog_put_bp(struct xfs_buf *); extern int xlog_bread(xlog_t *, xfs_daddr_t, int, struct xfs_buf *); -extern xfs_caddr_t xlog_align(xlog_t *, xfs_daddr_t, int, struct xfs_buf *); /* iclog tracing */ #define XLOG_TRACE_GRAB_FLUSH 1 diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 9824b5b..593e597 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -148,7 +148,7 @@ xlog_bread( * The buffer is kept locked across the write and is returned locked. * This can only be used for synchronous log writes. */ -int +STATIC int xlog_bwrite( xlog_t *log, xfs_daddr_t blk_no, @@ -179,7 +179,7 @@ xlog_bwrite( return error; } -xfs_caddr_t +STATIC xfs_caddr_t xlog_align( xlog_t *log, xfs_daddr_t blk_no, @@ -528,7 +528,7 @@ out: * * Return: zero if normal, non-zero if error. */ -int +STATIC int xlog_find_head( xlog_t *log, xfs_daddr_t *return_head_blk) diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 2ec967d..f618f6d 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -64,6 +64,7 @@ STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t); STATIC int xfs_uuid_mount(xfs_mount_t *); STATIC void xfs_uuid_unmount(xfs_mount_t *mp); +STATIC void xfs_unmountfs_wait(xfs_mount_t *); static struct { short offset; @@ -555,7 +556,7 @@ xfs_readsb(xfs_mount_t *mp) * fields from the superblock associated with the given * mount structure */ -void +STATIC void xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) { int i; @@ -1146,7 +1147,7 @@ xfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr) xfs_free_buftarg(mp->m_ddev_targp, 0); } -void +STATIC void xfs_unmountfs_wait(xfs_mount_t *mp) { if (mp->m_logdev_targp != mp->m_ddev_targp) diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 30dd08f..cd5170e 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -544,7 +544,6 @@ extern void xfs_mount_free(xfs_mount_t *mp, int remove_bhv); extern int xfs_mountfs(struct vfs *, xfs_mount_t *mp, int); extern int xfs_unmountfs(xfs_mount_t *, struct cred *); -extern void xfs_unmountfs_wait(xfs_mount_t *); extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *); extern int xfs_unmountfs_writesb(xfs_mount_t *); extern int xfs_unmount_flush(xfs_mount_t *, int); diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index a865f60..06dfca5 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -532,7 +532,7 @@ xfs_trans_apply_sb_deltas( * * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). */ -void +STATIC void xfs_trans_unreserve_and_mod_sb( xfs_trans_t *tp) { diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index b537366..fb1ae6c 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -1681,7 +1681,7 @@ suffix_strtoul(const char *cp, char **endp, unsigned int base) return simple_strtoul(cp, endp, base) << shift_left_factor; } -int +STATIC int xfs_parseargs( struct bhv_desc *bhv, char *options, @@ -1867,7 +1867,7 @@ printk("XFS: irixsgid is now a sysctl(2) variable, option is deprecated.\n"); return 0; } -int +STATIC int xfs_showargs( struct bhv_desc *bhv, struct seq_file *m) diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 25a5266..5703783 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -4028,7 +4028,7 @@ xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock) * errno on error * */ -int +STATIC int xfs_alloc_file_space( xfs_inode_t *ip, xfs_off_t offset, -- cgit v0.10.2 From efa8027804b2bd8eb7d4b41a1f5b738c36e44e8c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:37:17 +1000 Subject: [XFS] rewrite xfs_iflush_all SGI-PV: 936890 SGI-Modid: xfs-linux:xfs-kern:193349a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 9942163..a2c723b 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -3556,107 +3556,43 @@ corrupt_out: /* - * Flush all inactive inodes in mp. Return true if no user references - * were found, false otherwise. + * Flush all inactive inodes in mp. */ -int +void xfs_iflush_all( - xfs_mount_t *mp, - int flag) + xfs_mount_t *mp) { - int busy; - int done; - int purged; xfs_inode_t *ip; - vmap_t vmap; vnode_t *vp; - busy = done = 0; - while (!done) { - purged = 0; - XFS_MOUNT_ILOCK(mp); - ip = mp->m_inodes; - if (ip == NULL) { - break; - } - do { - /* Make sure we skip markers inserted by sync */ - if (ip->i_mount == NULL) { - ip = ip->i_mnext; - continue; - } - - /* - * It's up to our caller to purge the root - * and quota vnodes later. - */ - vp = XFS_ITOV_NULL(ip); - - if (!vp) { - XFS_MOUNT_IUNLOCK(mp); - xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC); - purged = 1; - break; - } + again: + XFS_MOUNT_ILOCK(mp); + ip = mp->m_inodes; + if (ip == NULL) + goto out; - if (vn_count(vp) != 0) { - if (vn_count(vp) == 1 && - (ip == mp->m_rootip || - (mp->m_quotainfo && - (ip->i_ino == mp->m_sb.sb_uquotino || - ip->i_ino == mp->m_sb.sb_gquotino)))) { + do { + /* Make sure we skip markers inserted by sync */ + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } - ip = ip->i_mnext; - continue; - } - if (!(flag & XFS_FLUSH_ALL)) { - busy = 1; - done = 1; - break; - } - /* - * Ignore busy inodes but continue flushing - * others. - */ - ip = ip->i_mnext; - continue; - } - /* - * Sample vp mapping while holding mp locked on MP - * systems, so we don't purge a reclaimed or - * nonexistent vnode. We break from the loop - * since we know that we modify - * it by pulling ourselves from it in xfs_reclaim() - * called via vn_purge() below. Set ip to the next - * entry in the list anyway so we'll know below - * whether we reached the end or not. - */ - VMAP(vp, vmap); + vp = XFS_ITOV_NULL(ip); + if (!vp) { XFS_MOUNT_IUNLOCK(mp); + xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC); + goto again; + } - vn_purge(vp, &vmap); + ASSERT(vn_count(vp) == 0); - purged = 1; - break; - } while (ip != mp->m_inodes); - /* - * We need to distinguish between when we exit the loop - * after a purge and when we simply hit the end of the - * list. We can't use the (ip == mp->m_inodes) test, - * because when we purge an inode at the start of the list - * the next inode on the list becomes mp->m_inodes. That - * would cause such a test to bail out early. The purged - * variable tells us how we got out of the loop. - */ - if (!purged) { - done = 1; - } - } + ip = ip->i_mnext; + } while (ip != mp->m_inodes); + out: XFS_MOUNT_IUNLOCK(mp); - return !busy; } - /* * xfs_iaccess: check accessibility of inode for mode. */ diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 2c9a7c4..54d9e54 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -412,11 +412,6 @@ void xfs_ifork_next_set(xfs_inode_t *ip, int w, int n); #define XFS_IFLUSH_DELWRI 5 /* - * Flags for xfs_iflush_all. - */ -#define XFS_FLUSH_ALL 0x1 - -/* * Flags for xfs_itruncate_start(). */ #define XFS_ITRUNC_DEFINITE 0x1 @@ -520,7 +515,7 @@ void xfs_ipin(xfs_inode_t *); void xfs_iunpin(xfs_inode_t *); int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_t *, int); int xfs_iflush(xfs_inode_t *, uint); -int xfs_iflush_all(struct xfs_mount *, int); +void xfs_iflush_all(struct xfs_mount *); int xfs_iaccess(xfs_inode_t *, mode_t, cred_t *); uint xfs_iroundup(uint); void xfs_ichgtime(xfs_inode_t *, int); diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index f618f6d..5b363fc 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1082,7 +1082,7 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) int64_t fsid; #endif - xfs_iflush_all(mp, XFS_FLUSH_ALL); + xfs_iflush_all(mp); XFS_QM_DQPURGEALL(mp, XFS_QMOPT_UQUOTA | XFS_QMOPT_GQUOTA | XFS_QMOPT_UMOUNTING); -- cgit v0.10.2 From 66f58d236fd9c2676545678374d58d48206bdbfa Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:37:43 +1000 Subject: [XFS] simplify XFS_PURGE_INODE SGI-PV: 936891 SGI-Modid: xfs-linux:xfs-kern:193408a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h index 414b600..675f03f 100644 --- a/fs/xfs/quota/xfs_quota_priv.h +++ b/fs/xfs/quota/xfs_quota_priv.h @@ -177,13 +177,7 @@ for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \ (!((dqp)->q_core.d_id)) #define XFS_PURGE_INODE(ip) \ - { \ - vmap_t dqvmap; \ - vnode_t *dqvp; \ - dqvp = XFS_ITOV(ip); \ - VMAP(dqvp, dqvmap); \ - VN_RELE(dqvp); \ - } + IRELE(ip); #define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \ (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???")) -- cgit v0.10.2 From 8401e9631c26dca9ebbc6997ac445fd49b06c79e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:38:03 +1000 Subject: [XFS] remove xfs_incore_relse SGI-PV: 936977 SGI-Modid: xfs-linux:xfs-kern:193409a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 049f871..c60e694 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1563,16 +1563,6 @@ xfs_free_buftarg( kmem_free(btp, sizeof(*btp)); } -void -xfs_incore_relse( - xfs_buftarg_t *btp, - int delwri_only, - int wait) -{ - invalidate_bdev(btp->pbr_bdev, 1); - truncate_inode_pages(btp->pbr_mapping, 0LL); -} - STATIC int xfs_setsize_buftarg_flags( xfs_buftarg_t *btp, diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index 74deed8..3f8f69a 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -576,7 +576,6 @@ extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *, int); extern void xfs_free_buftarg(xfs_buftarg_t *, int); extern void xfs_wait_buftarg(xfs_buftarg_t *); extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); -extern void xfs_incore_relse(xfs_buftarg_t *, int, int); extern int xfs_flush_buftarg(xfs_buftarg_t *, int); #define xfs_getsize_buftarg(buftarg) \ diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 5b363fc..82e1646 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1112,15 +1112,6 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) */ ASSERT(mp->m_inodes == NULL); - /* - * We may have bufs that are in the process of getting written still. - * We must wait for the I/O completion of those. The sync flag here - * does a two pass iteration thru the bufcache. - */ - if (XFS_FORCED_SHUTDOWN(mp)) { - xfs_incore_relse(mp->m_ddev_targp, 0, 1); /* synchronous */ - } - xfs_unmountfs_close(mp, cr); if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) xfs_uuid_unmount(mp); -- cgit v0.10.2 From c8ad20ffeb592d66ea869c57f8c525a9d727c67b Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Tue, 21 Jun 2005 15:38:48 +1000 Subject: [XFS] Add support for project quota, based on Dan Knappes earlier work. SGI-PV: 932952 SGI-Modid: xfs-linux:xfs-kern:22805a Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index 71bb410..44eb313 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h @@ -230,8 +230,10 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh) * field (see the QCMD macro in quota.h). These macros help keep the * code portable - they are not visible from the syscall interface. */ -#define Q_XSETGQLIM XQM_CMD(0x8) /* set groups disk limits */ -#define Q_XGETGQUOTA XQM_CMD(0x9) /* get groups disk limits */ +#define Q_XSETGQLIM XQM_CMD(8) /* set groups disk limits */ +#define Q_XGETGQUOTA XQM_CMD(9) /* get groups disk limits */ +#define Q_XSETPQLIM XQM_CMD(10) /* set projects disk limits */ +#define Q_XGETPQUOTA XQM_CMD(11) /* get projects disk limits */ /* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */ /* we may well need to fine-tune this if it ever becomes an issue. */ diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 455e2b2..d5f0340 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -701,7 +701,8 @@ linvfs_getxquota( struct vfs *vfsp = LINVFS_GET_VFS(sb); int error, getmode; - getmode = (type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETQUOTA; + getmode = (type == USRQUOTA) ? Q_XGETQUOTA : + ((type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETPQUOTA); VFS_QUOTACTL(vfsp, getmode, id, (caddr_t)fdq, error); return -error; } @@ -716,7 +717,8 @@ linvfs_setxquota( struct vfs *vfsp = LINVFS_GET_VFS(sb); int error, setmode; - setmode = (type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETQLIM; + setmode = (type == USRQUOTA) ? Q_XSETQLIM : + ((type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETPQLIM); VFS_QUOTACTL(vfsp, setmode, id, (caddr_t)fdq, error); return -error; } diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index 9ce4714..68089f5 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -399,9 +399,9 @@ xfs_qm_init_dquot_blk( for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++) xfs_qm_dqinit_core(curid, type, d); xfs_trans_dquot_buf(tp, bp, - type & XFS_DQ_USER ? - XFS_BLI_UDQUOT_BUF : - XFS_BLI_GDQUOT_BUF); + (type & XFS_DQ_USER ? XFS_BLI_UDQUOT_BUF : + ((type & XFS_DQ_PROJ) ? XFS_BLI_PDQUOT_BUF : + XFS_BLI_GDQUOT_BUF))); xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1); } @@ -482,8 +482,7 @@ xfs_qm_dqalloc( * the entire thing. */ xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT), - dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP), - bp); + dqp->dq_flags & XFS_DQ_ALLTYPES, bp); if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) { goto error1; @@ -613,8 +612,7 @@ xfs_qm_dqtobp( /* * A simple sanity check in case we got a corrupted dquot... */ - if (xfs_qm_dqcheck(ddq, id, - dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP), + if (xfs_qm_dqcheck(ddq, id, dqp->dq_flags & XFS_DQ_ALLTYPES, flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN), "dqtobp")) { if (!(flags & XFS_QMOPT_DQREPAIR)) { @@ -891,8 +889,8 @@ int xfs_qm_dqget( xfs_mount_t *mp, xfs_inode_t *ip, /* locked inode (optional) */ - xfs_dqid_t id, /* gid or uid, depending on type */ - uint type, /* UDQUOT or GDQUOT */ + xfs_dqid_t id, /* uid/projid/gid depending on type */ + uint type, /* XFS_DQ_USER/XFS_DQ_PROJ/XFS_DQ_GROUP */ uint flags, /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */ xfs_dquot_t **O_dqpp) /* OUT : locked incore dquot */ { @@ -903,7 +901,9 @@ xfs_qm_dqget( ASSERT(XFS_IS_QUOTA_RUNNING(mp)); if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) || + (! XFS_IS_PQUOTA_ON(mp) && type == XFS_DQ_PROJ) || (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) { +printk("XQM: ESRCH1\n"); return (ESRCH); } h = XFS_DQ_HASH(mp, id, type); @@ -921,7 +921,9 @@ xfs_qm_dqget( again: #ifdef DEBUG - ASSERT(type == XFS_DQ_USER || type == XFS_DQ_GROUP); + ASSERT(type == XFS_DQ_USER || + type == XFS_DQ_PROJ || + type == XFS_DQ_GROUP); if (ip) { ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); if (type == XFS_DQ_USER) @@ -979,6 +981,7 @@ xfs_qm_dqget( &dqp))) { if (ip) xfs_ilock(ip, XFS_ILOCK_EXCL); +if (error == ESRCH) printk("XQM: ESRCH2\n"); return (error); } @@ -1004,6 +1007,7 @@ xfs_qm_dqget( if (! XFS_IS_DQTYPE_ON(mp, type)) { /* inode stays locked on return */ xfs_qm_dqdestroy(dqp); +printk("XQM: ESRCH3\n"); return XFS_ERROR(ESRCH); } /* @@ -1244,8 +1248,8 @@ xfs_qm_dqflush( return (error); } - if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), 0, XFS_QMOPT_DOWARN, - "dqflush (incore copy)")) { + if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), + 0, XFS_QMOPT_DOWARN, "dqflush (incore copy)")) { xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE); return XFS_ERROR(EIO); } @@ -1397,7 +1401,8 @@ xfs_dqlock2( { if (d1 && d2) { ASSERT(d1 != d2); - if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > INT_GET(d2->q_core.d_id, ARCH_CONVERT)) { + if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > + INT_GET(d2->q_core.d_id, ARCH_CONVERT)) { xfs_dqlock(d2); xfs_dqlock(d1); } else { @@ -1520,8 +1525,7 @@ xfs_qm_dqprint(xfs_dquot_t *dqp) cmn_err(CE_DEBUG, "-----------KERNEL DQUOT----------------"); cmn_err(CE_DEBUG, "---- dquotID = %d", (int)INT_GET(dqp->q_core.d_id, ARCH_CONVERT)); - cmn_err(CE_DEBUG, "---- type = %s", - XFS_QM_ISUDQ(dqp) ? "USR" : "GRP"); + cmn_err(CE_DEBUG, "---- type = %s", DQFLAGTO_TYPESTR(dqp)); cmn_err(CE_DEBUG, "---- fs = 0x%p", dqp->q_mount); cmn_err(CE_DEBUG, "---- blkno = 0x%x", (int) dqp->q_blkno); cmn_err(CE_DEBUG, "---- boffset = 0x%x", (int) dqp->q_bufoffset); diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h index 35aeeaf..3917510 100644 --- a/fs/xfs/quota/xfs_dquot.h +++ b/fs/xfs/quota/xfs_dquot.h @@ -114,25 +114,18 @@ typedef struct xfs_dquot { #define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++) /* - * Quota Accounting flags + * Quota Accounting/Enforcement flags */ -#define XFS_ALL_QUOTA_ACCT (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT) -#define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD) -#define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD) -#define XFS_ALL_QUOTA_ACTV (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE) -#define XFS_ALL_QUOTA_ACCT_ENFD (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ - XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD) +#define XFS_ALL_QUOTA_ACCT \ + (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT) +#define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD) +#define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD) -#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT) -#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT) -#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT) - -/* - * Quota Limit Enforcement flags - */ +#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT) #define XFS_IS_QUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD) -#define XFS_IS_UQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_UQUOTA_ENFD) -#define XFS_IS_GQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_GQUOTA_ENFD) +#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT) +#define XFS_IS_PQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_PQUOTA_ACCT) +#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT) #ifdef DEBUG static inline int @@ -167,6 +160,8 @@ XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp) #define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp)) #define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) #define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER) +#define XFS_QM_ISPDQ(dqp) ((dqp)->dq_flags & XFS_DQ_PROJ) +#define XFS_QM_ISGDQ(dqp) ((dqp)->dq_flags & XFS_DQ_GROUP) #define XFS_DQ_TO_QINF(dqp) ((dqp)->q_mount->m_quotainfo) #define XFS_DQ_TO_QIP(dqp) (XFS_QM_ISUDQ(dqp) ? \ XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \ @@ -174,7 +169,7 @@ XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp) #define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \ (XFS_IS_UQUOTA_ON((d)->q_mount)) : \ - (XFS_IS_GQUOTA_ON((d)->q_mount)))) + (XFS_IS_OQUOTA_ON((d)->q_mount)))) #ifdef XFS_DQUOT_TRACE /* diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 41bbc49..3ea7597 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -310,9 +310,9 @@ xfs_qm_mount_quotainit( uint flags) { /* - * User or group quotas has to be on. + * User, projects or group quotas has to be on. */ - ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA)); + ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_PQUOTA | XFSMNT_GQUOTA)); /* * Initialize the flags in the mount structure. From this point @@ -330,7 +330,11 @@ xfs_qm_mount_quotainit( if (flags & XFSMNT_GQUOTA) { mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); if (flags & XFSMNT_GQUOTAENF) - mp->m_qflags |= XFS_GQUOTA_ENFD; + mp->m_qflags |= XFS_OQUOTA_ENFD; + } else if (flags & XFSMNT_PQUOTA) { + mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); + if (flags & XFSMNT_PQUOTAENF) + mp->m_qflags |= XFS_OQUOTA_ENFD; } } @@ -363,11 +367,11 @@ xfs_qm_mount_quotas( /* * If a file system had quotas running earlier, but decided to - * mount without -o quota/uquota/gquota options, revoke the + * mount without -o uquota/pquota/gquota options, revoke the * quotachecked license, and bail out. */ if (! XFS_IS_QUOTA_ON(mp) && - (mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) { + (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT)) { mp->m_qflags = 0; goto write_changes; } @@ -619,7 +623,7 @@ xfs_qm_detach_gdquots( STATIC int xfs_qm_dqpurge_int( xfs_mount_t *mp, - uint flags) /* QUOTAOFF/UMOUNTING/UQUOTA/GQUOTA */ + uint flags) /* QUOTAOFF/UMOUNTING/UQUOTA/PQUOTA/GQUOTA */ { xfs_dquot_t *dqp; uint dqtype; @@ -631,6 +635,7 @@ xfs_qm_dqpurge_int( return (0); dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0; + dqtype |= (flags & XFS_QMOPT_PQUOTA) ? XFS_DQ_PROJ : 0; dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0; xfs_qm_mplist_lock(mp); @@ -740,11 +745,11 @@ xfs_qm_dqattach_one( /* * udqhint is the i_udquot field in inode, and is non-NULL only - * when the type arg is XFS_DQ_GROUP. Its purpose is to save a + * when the type arg is group/project. Its purpose is to save a * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside * the user dquot. */ - ASSERT(!udqhint || type == XFS_DQ_GROUP); + ASSERT(!udqhint || type == XFS_DQ_GROUP || type == XFS_DQ_PROJ); if (udqhint && !dolock) xfs_dqlock(udqhint); @@ -903,8 +908,8 @@ xfs_qm_dqattach_grouphint( /* - * Given a locked inode, attach dquot(s) to it, taking UQUOTAON / GQUOTAON - * in to account. + * Given a locked inode, attach dquot(s) to it, taking U/G/P-QUOTAON + * into account. * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed. * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty * much made this code a complete mess, but it has been pretty useful. @@ -943,8 +948,13 @@ xfs_qm_dqattach( nquotas++; } ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); - if (XFS_IS_GQUOTA_ON(mp)) { - error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP, + if (XFS_IS_OQUOTA_ON(mp)) { + error = XFS_IS_GQUOTA_ON(mp) ? + xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP, + flags & XFS_QMOPT_DQALLOC, + flags & XFS_QMOPT_DQLOCK, + ip->i_udquot, &ip->i_gdquot) : + xfs_qm_dqattach_one(ip, ip->i_d.di_projid, XFS_DQ_PROJ, flags & XFS_QMOPT_DQALLOC, flags & XFS_QMOPT_DQLOCK, ip->i_udquot, &ip->i_gdquot); @@ -995,7 +1005,7 @@ xfs_qm_dqattach( } if (XFS_IS_UQUOTA_ON(mp)) ASSERT(ip->i_udquot); - if (XFS_IS_GQUOTA_ON(mp)) + if (XFS_IS_OQUOTA_ON(mp)) ASSERT(ip->i_gdquot); } #endif @@ -1024,13 +1034,13 @@ xfs_qm_dqdetach( ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino); ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino); - if (ip->i_udquot) - xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip); if (ip->i_udquot) { + xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip); xfs_qm_dqrele(ip->i_udquot); ip->i_udquot = NULL; } if (ip->i_gdquot) { + xfs_dqtrace_entry_ino(ip->i_gdquot, "DQDETTACH", ip); xfs_qm_dqrele(ip->i_gdquot); ip->i_gdquot = NULL; } @@ -1208,8 +1218,9 @@ xfs_qm_init_quotainfo( * and group quotas, at least not at this point. */ error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0, - (XFS_IS_UQUOTA_RUNNING(mp)) ? - XFS_DQ_USER : XFS_DQ_GROUP, + XFS_IS_UQUOTA_RUNNING(mp) ? XFS_DQ_USER : + (XFS_IS_GQUOTA_RUNNING(mp) ? XFS_DQ_GROUP : + XFS_DQ_PROJ), XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN, &dqp); if (! error) { @@ -1372,13 +1383,20 @@ xfs_qm_dqget_noattach( ASSERT(udqp); } - if (XFS_IS_GQUOTA_ON(mp)) { + if (XFS_IS_OQUOTA_ON(mp)) { ASSERT(ip->i_gdquot == NULL); if (udqp) xfs_dqunlock(udqp); - if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_gid, XFS_DQ_GROUP, - XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN, - &gdqp))) { + error = XFS_IS_GQUOTA_ON(mp) ? + xfs_qm_dqget(mp, ip, + ip->i_d.di_gid, XFS_DQ_GROUP, + XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN, + &gdqp) : + xfs_qm_dqget(mp, ip, + ip->i_d.di_projid, XFS_DQ_PROJ, + XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN, + &gdqp); + if (error) { if (udqp) xfs_qm_dqrele(udqp); ASSERT(error != ESRCH); @@ -1547,11 +1565,14 @@ xfs_qm_dqiter_bufs( int error; int notcommitted; int incr; + int type; ASSERT(blkcnt > 0); notcommitted = 0; incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ? XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt; + type = flags & XFS_QMOPT_UQUOTA ? XFS_DQ_USER : + (flags & XFS_QMOPT_PQUOTA ? XFS_DQ_PROJ : XFS_DQ_GROUP); error = 0; /* @@ -1570,9 +1591,7 @@ xfs_qm_dqiter_bufs( if (error) break; - (void) xfs_qm_reset_dqcounts(mp, bp, firstid, - flags & XFS_QMOPT_UQUOTA ? - XFS_DQ_USER : XFS_DQ_GROUP); + (void) xfs_qm_reset_dqcounts(mp, bp, firstid, type); xfs_bdwrite(mp, bp); /* * goto the next block. @@ -1584,7 +1603,7 @@ xfs_qm_dqiter_bufs( } /* - * Iterate over all allocated USR/GRP dquots in the system, calling a + * Iterate over all allocated USR/GRP/PRJ dquots in the system, calling a * caller supplied function for every chunk of dquots that we find. */ STATIC int @@ -1855,7 +1874,7 @@ xfs_qm_dqusage_adjust( xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks); xfs_qm_dqput(udqp); } - if (XFS_IS_GQUOTA_ON(mp)) { + if (XFS_IS_OQUOTA_ON(mp)) { ASSERT(gdqp); xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks); xfs_qm_dqput(gdqp); @@ -1904,7 +1923,7 @@ xfs_qm_quotacheck( cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname); /* - * First we go thru all the dquots on disk, USR and GRP, and reset + * First we go thru all the dquots on disk, USR and GRP/PRJ, and reset * their counters to zero. We need a clean slate. * We don't log our changes till later. */ @@ -1915,9 +1934,10 @@ xfs_qm_quotacheck( } if ((gip = XFS_QI_GQIP(mp))) { - if ((error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA))) + if ((error = xfs_qm_dqiterate(mp, gip, XFS_IS_GQUOTA_ON(mp) ? + XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA))) goto error_return; - flags |= XFS_GQUOTA_CHKD; + flags |= XFS_OQUOTA_CHKD; } do { @@ -1944,7 +1964,7 @@ xfs_qm_quotacheck( if (error) { xfs_qm_dqpurge_all(mp, XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA| - XFS_QMOPT_QUOTAOFF); + XFS_QMOPT_PQUOTA|XFS_QMOPT_QUOTAOFF); goto error_return; } /* @@ -1967,7 +1987,7 @@ xfs_qm_quotacheck( * quotachecked status, since we won't be doing accounting for * that type anymore. */ - mp->m_qflags &= ~(XFS_GQUOTA_CHKD | XFS_UQUOTA_CHKD); + mp->m_qflags &= ~(XFS_OQUOTA_CHKD | XFS_UQUOTA_CHKD); mp->m_qflags |= flags; XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++"); @@ -2019,7 +2039,7 @@ xfs_qm_init_quotainos( 0, 0, &uip, 0))) return XFS_ERROR(error); } - if (XFS_IS_GQUOTA_ON(mp) && + if (XFS_IS_OQUOTA_ON(mp) && mp->m_sb.sb_gquotino != NULLFSINO) { ASSERT(mp->m_sb.sb_gquotino > 0); if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, @@ -2049,10 +2069,12 @@ xfs_qm_init_quotainos( flags &= ~XFS_QMOPT_SBVERSION; } - if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) { - if ((error = xfs_qm_qino_alloc(mp, &gip, - sbflags | XFS_SB_GQUOTINO, - flags | XFS_QMOPT_GQUOTA))) { + if (XFS_IS_OQUOTA_ON(mp) && gip == NULL) { + flags |= (XFS_IS_GQUOTA_ON(mp) ? + XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA); + error = xfs_qm_qino_alloc(mp, &gip, + sbflags | XFS_SB_GQUOTINO, flags); + if (error) { if (uip) VN_RELE(XFS_ITOV(uip)); @@ -2458,6 +2480,7 @@ xfs_qm_vop_dqalloc( xfs_inode_t *ip, uid_t uid, gid_t gid, + prid_t prid, uint flags, xfs_dquot_t **O_udqpp, xfs_dquot_t **O_gdqpp) @@ -2489,8 +2512,7 @@ xfs_qm_vop_dqalloc( } uq = gq = NULL; - if ((flags & XFS_QMOPT_UQUOTA) && - XFS_IS_UQUOTA_ON(mp)) { + if ((flags & XFS_QMOPT_UQUOTA) && XFS_IS_UQUOTA_ON(mp)) { if (ip->i_d.di_uid != uid) { /* * What we need is the dquot that has this uid, and @@ -2528,8 +2550,7 @@ xfs_qm_vop_dqalloc( xfs_dqunlock(uq); } } - if ((flags & XFS_QMOPT_GQUOTA) && - XFS_IS_GQUOTA_ON(mp)) { + if ((flags & XFS_QMOPT_GQUOTA) && XFS_IS_GQUOTA_ON(mp)) { if (ip->i_d.di_gid != gid) { xfs_iunlock(ip, lockflags); if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid, @@ -2552,6 +2573,29 @@ xfs_qm_vop_dqalloc( XFS_DQHOLD(gq); xfs_dqunlock(gq); } + } else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) { + if (ip->i_d.di_projid != prid) { + xfs_iunlock(ip, lockflags); + if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid, + XFS_DQ_PROJ, + XFS_QMOPT_DQALLOC | + XFS_QMOPT_DOWARN, + &gq))) { + if (uq) + xfs_qm_dqrele(uq); + ASSERT(error != ENOENT); + return (error); + } + xfs_dqunlock(gq); + lockflags = XFS_ILOCK_SHARED; + xfs_ilock(ip, lockflags); + } else { + ASSERT(ip->i_gdquot); + gq = ip->i_gdquot; + xfs_dqlock(gq); + XFS_DQHOLD(gq); + xfs_dqunlock(gq); + } } if (uq) xfs_dqtrace_entry_ino(uq, "DQALLOC", ip); @@ -2617,7 +2661,7 @@ xfs_qm_vop_chown( } /* - * Quota reservations for setattr(AT_UID|AT_GID). + * Quota reservations for setattr(AT_UID|AT_GID|AT_PROJID). */ int xfs_qm_vop_chown_reserve( @@ -2652,12 +2696,16 @@ xfs_qm_vop_chown_reserve( unresudq = ip->i_udquot; } } - if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp && - ip->i_d.di_gid != INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) { - delblksgdq = gdqp; - if (delblks) { - ASSERT(ip->i_gdquot); - unresgdq = ip->i_gdquot; + if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) { + if ((XFS_IS_GQUOTA_ON(ip->i_mount) && ip->i_d.di_gid != + INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) || + (XFS_IS_PQUOTA_ON(ip->i_mount) && ip->i_d.di_projid != + INT_GET(gdqp->q_core.d_id, ARCH_CONVERT))) { + delblksgdq = gdqp; + if (delblks) { + ASSERT(ip->i_gdquot); + unresgdq = ip->i_gdquot; + } } } diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h index ae626ec..7819687 100644 --- a/fs/xfs/quota/xfs_qm.h +++ b/fs/xfs/quota/xfs_qm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -202,7 +202,7 @@ extern void xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint); /* vop stuff */ extern int xfs_qm_vop_dqalloc(xfs_mount_t *, xfs_inode_t *, - uid_t, gid_t, uint, + uid_t, gid_t, prid_t, uint, xfs_dquot_t **, xfs_dquot_t **); extern void xfs_qm_vop_dqattach_and_dqmod_newinode( xfs_trans_t *, xfs_inode_t *, diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c index 09b1171..dc3c37a 100644 --- a/fs/xfs/quota/xfs_qm_bhv.c +++ b/fs/xfs/quota/xfs_qm_bhv.c @@ -71,10 +71,13 @@ #define MNTOPT_NOQUOTA "noquota" /* no quotas */ #define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */ #define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */ +#define MNTOPT_PRJQUOTA "prjquota" /* project quota enabled */ #define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */ #define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */ +#define MNTOPT_PQUOTA "pquota" /* project quota (IRIX variant) */ #define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ +#define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */ #define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ STATIC int @@ -109,6 +112,14 @@ xfs_qm_parseargs( args->flags |= XFSMNT_UQUOTA; args->flags &= ~XFSMNT_UQUOTAENF; referenced = 1; + } else if (!strcmp(this_char, MNTOPT_PQUOTA) || + !strcmp(this_char, MNTOPT_PRJQUOTA)) { + args->flags |= XFSMNT_PQUOTA | XFSMNT_PQUOTAENF; + referenced = 1; + } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) { + args->flags |= XFSMNT_PQUOTA; + args->flags &= ~XFSMNT_PQUOTAENF; + referenced = 1; } else if (!strcmp(this_char, MNTOPT_GQUOTA) || !strcmp(this_char, MNTOPT_GRPQUOTA)) { args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF; @@ -127,6 +138,12 @@ xfs_qm_parseargs( *this_char++ = ','; } + if ((args->flags & XFSMNT_GQUOTA) && (args->flags & XFSMNT_PQUOTA)) { + cmn_err(CE_WARN, + "XFS: cannot mount with both project and group quota"); + return XFS_ERROR(EINVAL); + } + PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error); if (!error && !referenced) bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM); @@ -148,13 +165,19 @@ xfs_qm_showargs( seq_puts(m, "," MNTOPT_UQUOTANOENF); } + if (mp->m_qflags & XFS_PQUOTA_ACCT) { + (mp->m_qflags & XFS_OQUOTA_ENFD) ? + seq_puts(m, "," MNTOPT_PRJQUOTA) : + seq_puts(m, "," MNTOPT_PQUOTANOENF); + } + if (mp->m_qflags & XFS_GQUOTA_ACCT) { - (mp->m_qflags & XFS_GQUOTA_ENFD) ? + (mp->m_qflags & XFS_OQUOTA_ENFD) ? seq_puts(m, "," MNTOPT_GRPQUOTA) : seq_puts(m, "," MNTOPT_GQUOTANOENF); } - if (!(mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) + if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) seq_puts(m, "," MNTOPT_NOQUOTA); PVFS_SHOWARGS(BHV_NEXT(bhv), m, error); @@ -171,7 +194,7 @@ xfs_qm_mount( struct xfs_mount *mp = XFS_VFSTOM(vfsp); int error; - if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA)) + if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | XFSMNT_PQUOTA)) xfs_qm_mount_quotainit(mp, args->flags); PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error); return error; @@ -255,16 +278,17 @@ xfs_qm_newmount( uint *quotaflags) { uint quotaondisk; - uint uquotaondisk = 0, gquotaondisk = 0; + uint uquotaondisk = 0, gquotaondisk = 0, pquotaondisk = 0; *quotaflags = 0; *needquotamount = B_FALSE; quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && - mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT); + (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT); if (quotaondisk) { uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT; + pquotaondisk = mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT; gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT; } @@ -277,13 +301,16 @@ xfs_qm_newmount( if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) || (!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) || + (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) || + (!pquotaondisk && XFS_IS_PQUOTA_ON(mp)) || (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) || - (!gquotaondisk && XFS_IS_GQUOTA_ON(mp))) && + (!gquotaondisk && XFS_IS_OQUOTA_ON(mp))) && xfs_dev_is_read_only(mp, "changing quota state")) { cmn_err(CE_WARN, - "XFS: please mount with%s%s%s.", + "XFS: please mount with%s%s%s%s.", (!quotaondisk ? "out quota" : ""), (uquotaondisk ? " usrquota" : ""), + (pquotaondisk ? " prjquota" : ""), (gquotaondisk ? " grpquota" : "")); return XFS_ERROR(EPERM); } diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index 229f5b5..365a054 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c @@ -118,40 +118,41 @@ xfs_qm_quotactl( * The following commands are valid even when quotaoff. */ switch (cmd) { + case Q_XQUOTARM: /* - * truncate quota files. quota must be off. + * Truncate quota files. quota must be off. */ - case Q_XQUOTARM: if (XFS_IS_QUOTA_ON(mp) || addr == NULL) return XFS_ERROR(EINVAL); if (vfsp->vfs_flag & VFS_RDONLY) return XFS_ERROR(EROFS); return (xfs_qm_scall_trunc_qfiles(mp, xfs_qm_import_qtype_flags(*(uint *)addr))); + + case Q_XGETQSTAT: /* * Get quota status information. */ - case Q_XGETQSTAT: return (xfs_qm_scall_getqstat(mp, (fs_quota_stat_t *)addr)); + case Q_XQUOTAON: /* - * QUOTAON for root f/s and quota enforcement on others.. - * Quota accounting for non-root f/s's must be turned on - * at mount time. + * QUOTAON - enabling quota enforcement. + * Quota accounting must be turned on at mount time. */ - case Q_XQUOTAON: if (addr == NULL) return XFS_ERROR(EINVAL); if (vfsp->vfs_flag & VFS_RDONLY) return XFS_ERROR(EROFS); return (xfs_qm_scall_quotaon(mp, xfs_qm_import_flags(*(uint *)addr))); - case Q_XQUOTAOFF: + + case Q_XQUOTAOFF: if (vfsp->vfs_flag & VFS_RDONLY) return XFS_ERROR(EROFS); break; - default: + default: break; } @@ -159,7 +160,7 @@ xfs_qm_quotactl( return XFS_ERROR(ESRCH); switch (cmd) { - case Q_XQUOTAOFF: + case Q_XQUOTAOFF: if (vfsp->vfs_flag & VFS_RDONLY) return XFS_ERROR(EROFS); error = xfs_qm_scall_quotaoff(mp, @@ -167,42 +168,39 @@ xfs_qm_quotactl( B_FALSE); break; - /* - * Defaults to XFS_GETUQUOTA. - */ - case Q_XGETQUOTA: + case Q_XGETQUOTA: error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_USER, (fs_disk_quota_t *)addr); break; - /* - * Set limits, both hard and soft. Defaults to Q_SETUQLIM. - */ - case Q_XSETQLIM: + case Q_XGETGQUOTA: + error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, + (fs_disk_quota_t *)addr); + break; + case Q_XGETPQUOTA: + error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_PROJ, + (fs_disk_quota_t *)addr); + break; + + case Q_XSETQLIM: if (vfsp->vfs_flag & VFS_RDONLY) return XFS_ERROR(EROFS); error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_USER, (fs_disk_quota_t *)addr); break; - - case Q_XSETGQLIM: + case Q_XSETGQLIM: if (vfsp->vfs_flag & VFS_RDONLY) return XFS_ERROR(EROFS); error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, (fs_disk_quota_t *)addr); break; - - - case Q_XGETGQUOTA: - error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, - (fs_disk_quota_t *)addr); + case Q_XSETPQLIM: + if (vfsp->vfs_flag & VFS_RDONLY) + return XFS_ERROR(EROFS); + error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_PROJ, + (fs_disk_quota_t *)addr); break; - /* - * Quotas are entirely undefined after quotaoff in XFS quotas. - * For instance, there's no way to set limits when quotaoff. - */ - - default: + default: error = XFS_ERROR(EINVAL); break; } @@ -286,8 +284,12 @@ xfs_qm_scall_quotaoff( } if (flags & XFS_GQUOTA_ACCT) { dqtype |= XFS_QMOPT_GQUOTA; - flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD); + flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD); inactivate_flags |= XFS_GQUOTA_ACTIVE; + } else if (flags & XFS_PQUOTA_ACCT) { + dqtype |= XFS_QMOPT_PQUOTA; + flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD); + inactivate_flags |= XFS_PQUOTA_ACTIVE; } /* @@ -364,7 +366,8 @@ xfs_qm_scall_quotaoff( /* * If quotas is completely disabled, close shop. */ - if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) { + if (((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET1) || + ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET2)) { mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); xfs_qm_destroy_quotainfo(mp); return (0); @@ -378,7 +381,7 @@ xfs_qm_scall_quotaoff( XFS_PURGE_INODE(XFS_QI_UQIP(mp)); XFS_QI_UQIP(mp) = NULL; } - if ((dqtype & XFS_QMOPT_GQUOTA) && XFS_QI_GQIP(mp)) { + if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && XFS_QI_GQIP(mp)) { XFS_PURGE_INODE(XFS_QI_GQIP(mp)); XFS_QI_GQIP(mp) = NULL; } @@ -411,7 +414,8 @@ xfs_qm_scall_trunc_qfiles( } } - if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) { + if ((flags & (XFS_DQ_GROUP|XFS_DQ_PROJ)) && + mp->m_sb.sb_gquotino != NULLFSINO) { error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip, 0); if (! error) { (void) xfs_truncate_file(mp, qip); @@ -434,7 +438,7 @@ xfs_qm_scall_quotaon( uint flags) { int error; - unsigned long s; + unsigned long s; uint qf; uint accflags; __int64_t sbflags; @@ -468,9 +472,13 @@ xfs_qm_scall_quotaon( (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 && (flags & XFS_UQUOTA_ENFD)) || + ((flags & XFS_PQUOTA_ACCT) == 0 && + (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 && + (flags & XFS_OQUOTA_ENFD)) + || ((flags & XFS_GQUOTA_ACCT) == 0 && (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 && - (flags & XFS_GQUOTA_ENFD))) { + (flags & XFS_OQUOTA_ENFD))) { qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n", flags, mp->m_sb.sb_qflags); return XFS_ERROR(EINVAL); @@ -504,6 +512,10 @@ xfs_qm_scall_quotaon( */ if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) != (mp->m_qflags & XFS_UQUOTA_ACCT)) || + ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) != + (mp->m_qflags & XFS_PQUOTA_ACCT)) || + ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) != + (mp->m_qflags & XFS_GQUOTA_ACCT)) || (flags & XFS_ALL_QUOTA_ENFD) == 0) return (0); @@ -521,7 +533,6 @@ xfs_qm_scall_quotaon( } - /* * Return quota status information, such as uquota-off, enforcements, etc. */ @@ -776,9 +787,9 @@ xfs_qm_log_quotaoff_end( xfs_qoff_logitem_t *startqoff, uint flags) { - xfs_trans_t *tp; + xfs_trans_t *tp; int error; - xfs_qoff_logitem_t *qoffi; + xfs_qoff_logitem_t *qoffi; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END); @@ -928,18 +939,26 @@ xfs_qm_export_dquot( STATIC uint xfs_qm_import_qtype_flags( - uint uflags) + uint uflags) { + uint oflags = 0; + /* - * Can't be both at the same time. + * Can't be more than one, or none. */ if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == - (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) || - ((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == 0)) + (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) || + ((uflags & (XFS_GROUP_QUOTA | XFS_PROJ_QUOTA)) == + (XFS_GROUP_QUOTA | XFS_PROJ_QUOTA)) || + ((uflags & (XFS_USER_QUOTA | XFS_PROJ_QUOTA)) == + (XFS_USER_QUOTA | XFS_PROJ_QUOTA)) || + ((uflags & (XFS_GROUP_QUOTA|XFS_USER_QUOTA|XFS_PROJ_QUOTA)) == 0)) return (0); - return (uflags & XFS_USER_QUOTA) ? - XFS_DQ_USER : XFS_DQ_GROUP; + oflags |= (uflags & XFS_USER_QUOTA) ? XFS_DQ_USER : 0; + oflags |= (uflags & XFS_PROJ_QUOTA) ? XFS_DQ_PROJ : 0; + oflags |= (uflags & XFS_GROUP_QUOTA) ? XFS_DQ_GROUP: 0; + return oflags; } STATIC uint @@ -947,14 +966,19 @@ xfs_qm_export_qtype_flags( uint flags) { /* - * Can't be both at the same time. + * Can't be more than one, or none. */ - ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != - (XFS_GROUP_QUOTA | XFS_USER_QUOTA)); - ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != 0); + ASSERT((flags & (XFS_PROJ_QUOTA | XFS_USER_QUOTA)) != + (XFS_PROJ_QUOTA | XFS_USER_QUOTA)); + ASSERT((flags & (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)) != + (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)); + ASSERT((flags & (XFS_USER_QUOTA | XFS_GROUP_QUOTA)) != + (XFS_USER_QUOTA | XFS_GROUP_QUOTA)); + ASSERT((flags & (XFS_PROJ_QUOTA|XFS_USER_QUOTA|XFS_GROUP_QUOTA)) != 0); return (flags & XFS_DQ_USER) ? - XFS_USER_QUOTA : XFS_GROUP_QUOTA; + XFS_USER_QUOTA : (flags & XFS_DQ_PROJ) ? + XFS_PROJ_QUOTA : XFS_GROUP_QUOTA; } STATIC uint @@ -965,12 +989,14 @@ xfs_qm_import_flags( if (uflags & XFS_QUOTA_UDQ_ACCT) flags |= XFS_UQUOTA_ACCT; + if (uflags & XFS_QUOTA_PDQ_ACCT) + flags |= XFS_PQUOTA_ACCT; if (uflags & XFS_QUOTA_GDQ_ACCT) flags |= XFS_GQUOTA_ACCT; if (uflags & XFS_QUOTA_UDQ_ENFD) flags |= XFS_UQUOTA_ENFD; - if (uflags & XFS_QUOTA_GDQ_ENFD) - flags |= XFS_GQUOTA_ENFD; + if (uflags & (XFS_QUOTA_PDQ_ENFD|XFS_QUOTA_GDQ_ENFD)) + flags |= XFS_OQUOTA_ENFD; return (flags); } @@ -984,12 +1010,16 @@ xfs_qm_export_flags( uflags = 0; if (flags & XFS_UQUOTA_ACCT) uflags |= XFS_QUOTA_UDQ_ACCT; + if (flags & XFS_PQUOTA_ACCT) + uflags |= XFS_QUOTA_PDQ_ACCT; if (flags & XFS_GQUOTA_ACCT) uflags |= XFS_QUOTA_GDQ_ACCT; if (flags & XFS_UQUOTA_ENFD) uflags |= XFS_QUOTA_UDQ_ENFD; - if (flags & XFS_GQUOTA_ENFD) - uflags |= XFS_QUOTA_GDQ_ENFD; + if (flags & (XFS_OQUOTA_ENFD)) { + uflags |= (flags & XFS_GQUOTA_ACCT) ? + XFS_QUOTA_GDQ_ENFD : XFS_QUOTA_PDQ_ENFD; + } return (uflags); } @@ -1070,7 +1100,7 @@ again: xfs_qm_dqrele(ip->i_udquot); ip->i_udquot = NULL; } - if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) { + if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) { xfs_qm_dqrele(ip->i_gdquot); ip->i_gdquot = NULL; } @@ -1160,7 +1190,6 @@ xfs_qm_dqtest_print( { cmn_err(CE_DEBUG, "-----------DQTEST DQUOT----------------"); cmn_err(CE_DEBUG, "---- dquot ID = %d", d->d_id); - cmn_err(CE_DEBUG, "---- type = %s", XFS_QM_ISUDQ(d)? "USR" : "GRP"); cmn_err(CE_DEBUG, "---- fs = 0x%p", d->q_mount); cmn_err(CE_DEBUG, "---- bcount = %Lu (0x%x)", d->d_bcount, (int)d->d_bcount); @@ -1231,7 +1260,7 @@ xfs_dqtest_cmp2( #ifdef QUOTADEBUG if (!err) { cmn_err(CE_DEBUG, "%d [%s] [0x%p] qchecked", - d->d_id, XFS_QM_ISUDQ(d) ? "USR" : "GRP", d->q_mount); + d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount); } #endif return (err); @@ -1287,6 +1316,7 @@ STATIC void xfs_qm_internalqcheck_get_dquots( xfs_mount_t *mp, xfs_dqid_t uid, + xfs_dqid_t projid, xfs_dqid_t gid, xfs_dqtest_t **ud, xfs_dqtest_t **gd) @@ -1295,6 +1325,8 @@ xfs_qm_internalqcheck_get_dquots( xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud); if (XFS_IS_GQUOTA_ON(mp)) xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd); + else if (XFS_IS_PQUOTA_ON(mp)) + xfs_qm_internalqcheck_dqget(mp, projid, XFS_DQ_PROJ, gd); } @@ -1362,13 +1394,14 @@ xfs_qm_internalqcheck_adjust( } xfs_qm_internalqcheck_get_dquots(mp, (xfs_dqid_t) ip->i_d.di_uid, + (xfs_dqid_t) ip->i_d.di_projid, (xfs_dqid_t) ip->i_d.di_gid, &ud, &gd); if (XFS_IS_UQUOTA_ON(mp)) { ASSERT(ud); xfs_qm_internalqcheck_dqadjust(ip, ud); } - if (XFS_IS_GQUOTA_ON(mp)) { + if (XFS_IS_OQUOTA_ON(mp)) { ASSERT(gd); xfs_qm_internalqcheck_dqadjust(ip, gd); } diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h index 675f03f..472afd3 100644 --- a/fs/xfs/quota/xfs_quota_priv.h +++ b/fs/xfs/quota/xfs_quota_priv.h @@ -102,7 +102,8 @@ static inline int XQMISLCKD(struct xfs_dqhash *h) (xfs_Gqm->qm_grp_dqhtable + \ XFS_DQ_HASHVAL(mp, id))) #define XFS_IS_DQTYPE_ON(mp, type) (type == XFS_DQ_USER ? \ - XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp)) + XFS_IS_UQUOTA_ON(mp) : \ + XFS_IS_OQUOTA_ON(mp)) #define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \ !dqp->q_core.d_blk_hardlimit && \ !dqp->q_core.d_blk_softlimit && \ @@ -180,7 +181,8 @@ for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \ IRELE(ip); #define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \ - (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???")) + (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : \ + (((d)->dq_flags & XFS_DQ_PROJ) ? "PRJ":"???"))) #define DQFLAGTO_DIRTYSTR(d) (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY") #endif /* __XFS_QUOTA_PRIV_H__ */ diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c index 3644ca0..565efb7 100644 --- a/fs/xfs/quota/xfs_trans_dquot.c +++ b/fs/xfs/quota/xfs_trans_dquot.c @@ -207,12 +207,10 @@ xfs_trans_mod_dquot_byino( if (tp->t_dqinfo == NULL) xfs_trans_alloc_dqinfo(tp); - if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) { + if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta); - } - if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot) { + if (XFS_IS_OQUOTA_ON(mp) && ip->i_gdquot) (void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta); - } } STATIC xfs_dqtrx_t * diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index 5f1b0c9..01aed5f 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h @@ -80,7 +80,7 @@ typedef struct xfs_buf_log_format_t { * user or group dquots and may require special recovery handling. */ #define XFS_BLI_UDQUOT_BUF 0x4 -/* #define XFS_BLI_PDQUOT_BUF 0x8 */ +#define XFS_BLI_PDQUOT_BUF 0x8 #define XFS_BLI_GDQUOT_BUF 0x10 #define XFS_BLI_CHUNK 128 diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 593e597..91d764a 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -1964,7 +1964,8 @@ xlog_recover_do_reg_buffer( * probably a good thing to do for other buf types also. */ error = 0; - if (buf_f->blf_flags & (XFS_BLI_UDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) { + if (buf_f->blf_flags & + (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) { error = xfs_qm_dqcheck((xfs_disk_dquot_t *) item->ri_buf[i].i_addr, -1, 0, XFS_QMOPT_DOWARN, @@ -2030,6 +2031,7 @@ xfs_qm_dqcheck( } if (INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_USER && + INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_PROJ && INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_GROUP) { if (flags & XFS_QMOPT_DOWARN) cmn_err(CE_ALERT, @@ -2135,6 +2137,8 @@ xlog_recover_do_dquot_buffer( type = 0; if (buf_f->blf_flags & XFS_BLI_UDQUOT_BUF) type |= XFS_DQ_USER; + if (buf_f->blf_flags & XFS_BLI_PDQUOT_BUF) + type |= XFS_DQ_PROJ; if (buf_f->blf_flags & XFS_BLI_GDQUOT_BUF) type |= XFS_DQ_GROUP; /* @@ -2247,7 +2251,8 @@ xlog_recover_do_buffer_trans( error = 0; if (flags & XFS_BLI_INODE_BUF) { error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f); - } else if (flags & (XFS_BLI_UDQUOT_BUF | XFS_BLI_GDQUOT_BUF)) { + } else if (flags & + (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) { xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f); } else { xlog_recover_do_reg_buffer(mp, item, bp, buf_f); @@ -2619,7 +2624,7 @@ xlog_recover_do_dquot_trans( * This type of quotas was turned off, so ignore this record. */ type = INT_GET(recddq->d_flags, ARCH_CONVERT) & - (XFS_DQ_USER | XFS_DQ_GROUP); + (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP); ASSERT(type); if (log->l_quotaoffs_flag & type) return (0); diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index cd5170e..5affba3 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -141,7 +141,7 @@ typedef int (*xfs_dqattach_t)(struct xfs_inode *, uint); typedef void (*xfs_dqdetach_t)(struct xfs_inode *); typedef int (*xfs_dqpurgeall_t)(struct xfs_mount *, uint); typedef int (*xfs_dqvopalloc_t)(struct xfs_mount *, - struct xfs_inode *, uid_t, gid_t, uint, + struct xfs_inode *, uid_t, gid_t, prid_t, uint, struct xfs_dquot **, struct xfs_dquot **); typedef void (*xfs_dqvopcreate_t)(struct xfs_trans *, struct xfs_inode *, struct xfs_dquot *, struct xfs_dquot *); @@ -185,8 +185,8 @@ typedef struct xfs_qmops { (*(mp)->m_qm_ops.xfs_dqdetach)(ip) #define XFS_QM_DQPURGEALL(mp, fl) \ (*(mp)->m_qm_ops.xfs_dqpurgeall)(mp, fl) -#define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, fl, dq1, dq2) \ - (*(mp)->m_qm_ops.xfs_dqvopalloc)(mp, ip, uid, gid, fl, dq1, dq2) +#define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, prid, fl, dq1, dq2) \ + (*(mp)->m_qm_ops.xfs_dqvopalloc)(mp, ip, uid, gid, prid, fl, dq1, dq2) #define XFS_QM_DQVOPCREATE(mp, tp, ip, dq1, dq2) \ (*(mp)->m_qm_ops.xfs_dqvopcreate)(tp, ip, dq1, dq2) #define XFS_QM_DQVOPRENAME(mp, ip) \ diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index 703ec4e..341cb46 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h @@ -96,7 +96,7 @@ typedef struct xfs_dqblk { * flags for q_flags field in the dquot. */ #define XFS_DQ_USER 0x0001 /* a user quota */ -/* #define XFS_DQ_PROJ 0x0002 -- project quota (IRIX) */ +#define XFS_DQ_PROJ 0x0002 /* project quota */ #define XFS_DQ_GROUP 0x0004 /* a group quota */ #define XFS_DQ_FLOCKED 0x0008 /* flush lock taken */ #define XFS_DQ_DIRTY 0x0010 /* dquot is dirty */ @@ -104,6 +104,8 @@ typedef struct xfs_dqblk { #define XFS_DQ_INACTIVE 0x0040 /* dq off mplist & hashlist */ #define XFS_DQ_MARKER 0x0080 /* sentinel */ +#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP) + /* * In the worst case, when both user and group quotas are on, * we can have a max of three dquots changing in a single transaction. @@ -124,7 +126,7 @@ typedef struct xfs_dqblk { typedef struct xfs_dq_logformat { __uint16_t qlf_type; /* dquot log item type */ __uint16_t qlf_size; /* size of this item */ - xfs_dqid_t qlf_id; /* usr/grp id number : 32 bits */ + xfs_dqid_t qlf_id; /* usr/grp/proj id : 32 bits */ __int64_t qlf_blkno; /* blkno of dquot buffer */ __int32_t qlf_len; /* len of dquot buffer */ __uint32_t qlf_boffset; /* off of dquot in buffer */ @@ -152,9 +154,9 @@ typedef struct xfs_qoff_logformat { #define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */ #define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */ #define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */ -#define XFS_PQUOTA_ACCT 0x0008 /* (IRIX) project quota accounting ON */ -#define XFS_GQUOTA_ENFD 0x0010 /* group quota limits enforced */ -#define XFS_GQUOTA_CHKD 0x0020 /* quotacheck run on grp quotas */ +#define XFS_PQUOTA_ACCT 0x0008 /* project quota accounting ON */ +#define XFS_OQUOTA_ENFD 0x0010 /* other (grp/prj) quota limits enforced */ +#define XFS_OQUOTA_CHKD 0x0020 /* quotacheck run on other (grp/prj) quotas */ #define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */ /* @@ -162,17 +164,22 @@ typedef struct xfs_qoff_logformat { * are in the process of getting turned off. These flags are in m_qflags but * never in sb_qflags. */ -#define XFS_UQUOTA_ACTIVE 0x0080 /* uquotas are being turned off */ -#define XFS_GQUOTA_ACTIVE 0x0100 /* gquotas are being turned off */ +#define XFS_UQUOTA_ACTIVE 0x0100 /* uquotas are being turned off */ +#define XFS_PQUOTA_ACTIVE 0x0200 /* pquotas are being turned off */ +#define XFS_GQUOTA_ACTIVE 0x0400 /* gquotas are being turned off */ /* * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees * quota will be not be switched off as long as that inode lock is held. */ #define XFS_IS_QUOTA_ON(mp) ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \ - XFS_GQUOTA_ACTIVE)) + XFS_GQUOTA_ACTIVE | \ + XFS_PQUOTA_ACTIVE)) +#define XFS_IS_OQUOTA_ON(mp) ((mp)->m_qflags & (XFS_GQUOTA_ACTIVE | \ + XFS_PQUOTA_ACTIVE)) #define XFS_IS_UQUOTA_ON(mp) ((mp)->m_qflags & XFS_UQUOTA_ACTIVE) #define XFS_IS_GQUOTA_ON(mp) ((mp)->m_qflags & XFS_GQUOTA_ACTIVE) +#define XFS_IS_PQUOTA_ON(mp) ((mp)->m_qflags & XFS_PQUOTA_ACTIVE) /* * Flags to tell various functions what to do. Not all of these are meaningful @@ -182,7 +189,7 @@ typedef struct xfs_qoff_logformat { #define XFS_QMOPT_DQLOCK 0x0000001 /* dqlock */ #define XFS_QMOPT_DQALLOC 0x0000002 /* alloc dquot ondisk if needed */ #define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */ -#define XFS_QMOPT_GQUOTA 0x0000008 /* group dquot requested */ +#define XFS_QMOPT_PQUOTA 0x0000008 /* project dquot requested */ #define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */ #define XFS_QMOPT_DQSUSER 0x0000020 /* don't cache super users dquot */ #define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */ @@ -192,6 +199,7 @@ typedef struct xfs_qoff_logformat { #define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if necessary */ #define XFS_QMOPT_ILOCKED 0x0000800 /* inode is already locked (excl) */ #define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot, if damaged. */ +#define XFS_QMOPT_GQUOTA 0x0002000 /* group dquot requested */ /* * flags to xfs_trans_mod_dquot to indicate which field needs to be @@ -231,7 +239,8 @@ typedef struct xfs_qoff_logformat { #define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT -#define XFS_QMOPT_QUOTALL (XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA) +#define XFS_QMOPT_QUOTALL \ + (XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA) #define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) #ifdef __KERNEL__ @@ -246,21 +255,33 @@ typedef struct xfs_qoff_logformat { */ #define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\ (ip)->i_udquot == NULL) || \ - (XFS_IS_GQUOTA_ON(mp) && \ + (XFS_IS_OQUOTA_ON(mp) && \ (ip)->i_gdquot == NULL)) -#define XFS_QM_NEED_QUOTACHECK(mp) ((XFS_IS_UQUOTA_ON(mp) && \ - (mp->m_sb.sb_qflags & \ - XFS_UQUOTA_CHKD) == 0) || \ - (XFS_IS_GQUOTA_ON(mp) && \ - (mp->m_sb.sb_qflags & \ - XFS_GQUOTA_CHKD) == 0)) +#define XFS_QM_NEED_QUOTACHECK(mp) \ + ((XFS_IS_UQUOTA_ON(mp) && \ + (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD) == 0) || \ + (XFS_IS_GQUOTA_ON(mp) && \ + ((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \ + (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT))) || \ + (XFS_IS_PQUOTA_ON(mp) && \ + ((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \ + (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT)))) + +#define XFS_MOUNT_QUOTA_SET1 (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ + XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\ + XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD) + +#define XFS_MOUNT_QUOTA_SET2 (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ + XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\ + XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD) #define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ - XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\ - XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD) + XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\ + XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD|\ + XFS_GQUOTA_ACCT) #define XFS_MOUNT_QUOTA_MASK (XFS_MOUNT_QUOTA_ALL | XFS_UQUOTA_ACTIVE | \ - XFS_GQUOTA_ACTIVE) + XFS_GQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE) /* diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index a9682b9..144da7a 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c @@ -976,6 +976,7 @@ xfs_trans_dquot_buf( ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); ASSERT(type == XFS_BLI_UDQUOT_BUF || + type == XFS_BLI_PDQUOT_BUF || type == XFS_BLI_GDQUOT_BUF); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c index d1f8146..11351f0 100644 --- a/fs/xfs/xfs_utils.c +++ b/fs/xfs/xfs_utils.c @@ -428,7 +428,7 @@ xfs_truncate_file( if (ip->i_ino != mp->m_sb.sb_uquotino) ASSERT(ip->i_udquot); } - if (XFS_IS_GQUOTA_ON(mp)) { + if (XFS_IS_OQUOTA_ON(mp)) { if (ip->i_ino != mp->m_sb.sb_gquotino) ASSERT(ip->i_gdquot); } diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index fb1ae6c..1035004 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -368,16 +368,6 @@ xfs_finish_flags( } /* - * disallow mount attempts with (IRIX) project quota enabled - */ - if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && - (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT)) { - cmn_err(CE_WARN, - "XFS: cannot mount a filesystem with IRIX project quota enabled"); - return XFS_ERROR(ENOSYS); - } - - /* * check for shared mount. */ if (ap->flags & XFSMNT_SHARED) { diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 5703783..695978b 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -351,21 +351,28 @@ xfs_setattr( * If the IDs do change before we take the ilock, we're covered * because the i_*dquot fields will get updated anyway. */ - if (XFS_IS_QUOTA_ON(mp) && (mask & (XFS_AT_UID|XFS_AT_GID))) { + if (XFS_IS_QUOTA_ON(mp) && + (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) { uint qflags = 0; - if (mask & XFS_AT_UID) { + if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) { uid = vap->va_uid; qflags |= XFS_QMOPT_UQUOTA; } else { uid = ip->i_d.di_uid; } - if (mask & XFS_AT_GID) { + if ((mask & XFS_AT_GID) && XFS_IS_GQUOTA_ON(mp)) { gid = vap->va_gid; qflags |= XFS_QMOPT_GQUOTA; } else { gid = ip->i_d.di_gid; } + if ((mask & XFS_AT_PROJID) && XFS_IS_PQUOTA_ON(mp)) { + projid = vap->va_projid; + qflags |= XFS_QMOPT_PQUOTA; + } else { + projid = ip->i_d.di_projid; + } /* * We take a reference when we initialize udqp and gdqp, * so it is important that we never blindly double trip on @@ -373,7 +380,8 @@ xfs_setattr( */ ASSERT(udqp == NULL); ASSERT(gdqp == NULL); - code = XFS_QM_DQVOPALLOC(mp, ip, uid,gid, qflags, &udqp, &gdqp); + code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags, + &udqp, &gdqp); if (code) return (code); } @@ -510,10 +518,11 @@ xfs_setattr( goto error_return; } /* - * Do a quota reservation only if uid or gid is actually + * Do a quota reservation only if uid/projid/gid is actually * going to change. */ if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || + (XFS_IS_PQUOTA_ON(mp) && iprojid != projid) || (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { ASSERT(tp); code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, @@ -774,6 +783,7 @@ xfs_setattr( } if (igid != gid) { if (XFS_IS_GQUOTA_ON(mp)) { + ASSERT(!XFS_IS_PQUOTA_ON(mp)); ASSERT(mask & XFS_AT_GID); ASSERT(gdqp); olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, @@ -782,6 +792,13 @@ xfs_setattr( ip->i_d.di_gid = gid; } if (iprojid != projid) { + if (XFS_IS_PQUOTA_ON(mp)) { + ASSERT(!XFS_IS_GQUOTA_ON(mp)); + ASSERT(mask & XFS_AT_PROJID); + ASSERT(gdqp); + olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, + &ip->i_gdquot, gdqp); + } ip->i_d.di_projid = projid; /* * We may have to rev the inode as well as @@ -1907,7 +1924,7 @@ xfs_create( * Make sure that we have allocated dquot(s) on disk. */ error = XFS_QM_DQVOPALLOC(mp, dp, - current_fsuid(credp), current_fsgid(credp), + current_fsuid(credp), current_fsgid(credp), prid, XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp); if (error) goto std_return; @@ -2812,7 +2829,7 @@ xfs_mkdir( * Make sure that we have allocated dquot(s) on disk. */ error = XFS_QM_DQVOPALLOC(mp, dp, - current_fsuid(credp), current_fsgid(credp), + current_fsuid(credp), current_fsgid(credp), prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); if (error) goto std_return; @@ -3366,7 +3383,7 @@ xfs_symlink( * Make sure that we have allocated dquot(s) on disk. */ error = XFS_QM_DQVOPALLOC(mp, dp, - current_fsuid(credp), current_fsgid(credp), + current_fsuid(credp), current_fsgid(credp), prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); if (error) goto std_return; -- cgit v0.10.2 From 365ca83d509f77f2095976edb8d10ca6e9d86d58 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Tue, 21 Jun 2005 15:39:12 +1000 Subject: [XFS] Add support for project quota inheritance, a merge of Glens changes. SGI-PV: 932952 SGI-Modid: xfs-linux:xfs-kern:22806a Signed-off-by: Nathan Scott diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index a2c723b..34bdf59 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1202,26 +1202,32 @@ xfs_ialloc( case S_IFREG: case S_IFDIR: if (unlikely(pip->i_d.di_flags & XFS_DIFLAG_ANY)) { - if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) { - if ((mode & S_IFMT) == S_IFDIR) { - ip->i_d.di_flags |= XFS_DIFLAG_RTINHERIT; - } else { - ip->i_d.di_flags |= XFS_DIFLAG_REALTIME; + uint di_flags = 0; + + if ((mode & S_IFMT) == S_IFDIR) { + if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) + di_flags |= XFS_DIFLAG_RTINHERIT; + } else { + if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) { + di_flags |= XFS_DIFLAG_REALTIME; ip->i_iocore.io_flags |= XFS_IOCORE_RT; } } if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) && xfs_inherit_noatime) - ip->i_d.di_flags |= XFS_DIFLAG_NOATIME; + di_flags |= XFS_DIFLAG_NOATIME; if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) && xfs_inherit_nodump) - ip->i_d.di_flags |= XFS_DIFLAG_NODUMP; + di_flags |= XFS_DIFLAG_NODUMP; if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) && xfs_inherit_sync) - ip->i_d.di_flags |= XFS_DIFLAG_SYNC; + di_flags |= XFS_DIFLAG_SYNC; if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) && xfs_inherit_nosymlinks) - ip->i_d.di_flags |= XFS_DIFLAG_NOSYMLINKS; + di_flags |= XFS_DIFLAG_NOSYMLINKS; + if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) + di_flags |= XFS_DIFLAG_PROJINHERIT; + ip->i_d.di_flags |= di_flags; } /* FALLTHROUGH */ case S_IFLNK: diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 695978b..96dc18b 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -507,8 +507,6 @@ xfs_setattr( * that the group ID supplied to the chown() function * shall be equal to either the group ID or one of the * supplementary group IDs of the calling process. - * - * XXX: How does restricted_chown affect projid? */ if (restricted_chown && (iuid != uid || (igid != gid && @@ -860,6 +858,8 @@ xfs_setattr( di_flags |= XFS_DIFLAG_NOATIME; if (vap->va_xflags & XFS_XFLAG_NODUMP) di_flags |= XFS_DIFLAG_NODUMP; + if (vap->va_xflags & XFS_XFLAG_PROJINHERIT) + di_flags |= XFS_DIFLAG_PROJINHERIT; if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { if (vap->va_xflags & XFS_XFLAG_RTINHERIT) di_flags |= XFS_DIFLAG_RTINHERIT; @@ -1915,7 +1915,9 @@ xfs_create( /* Return through std_return after this point. */ udqp = gdqp = NULL; - if (vap->va_mask & XFS_AT_PROJID) + if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) + prid = dp->i_d.di_projid; + else if (vap->va_mask & XFS_AT_PROJID) prid = (xfs_prid_t)vap->va_projid; else prid = (xfs_prid_t)dfltprid; @@ -2621,17 +2623,7 @@ xfs_link( if (src_vp->v_type == VDIR) return XFS_ERROR(EPERM); - /* - * For now, manually find the XFS behavior descriptor for - * the source vnode. If it doesn't exist then something - * is wrong and we should just return an error. - * Eventually we need to figure out how link is going to - * work in the face of stacked vnodes. - */ src_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(src_vp), &xfs_vnodeops); - if (src_bdp == NULL) { - return XFS_ERROR(EXDEV); - } sip = XFS_BHVTOI(src_bdp); tdp = XFS_BHVTOI(target_dir_bdp); mp = tdp->i_mount; @@ -2698,6 +2690,17 @@ xfs_link( goto error_return; } + /* + * If we are using project inheritance, we only allow hard link + * creation in our tree when the project IDs are the same; else + * the tree quota mechanism could be circumvented. + */ + if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && + (tdp->i_d.di_projid != sip->i_d.di_projid))) { + error = XFS_ERROR(EPERM); + goto error_return; + } + if (resblks == 0 && (error = XFS_DIR_CANENTER(mp, tp, tdp, target_name, target_namelen))) @@ -2820,7 +2823,9 @@ xfs_mkdir( mp = dp->i_mount; udqp = gdqp = NULL; - if (vap->va_mask & XFS_AT_PROJID) + if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) + prid = dp->i_d.di_projid; + else if (vap->va_mask & XFS_AT_PROJID) prid = (xfs_prid_t)vap->va_projid; else prid = (xfs_prid_t)dfltprid; @@ -3374,7 +3379,9 @@ xfs_symlink( /* Return through std_return after this point. */ udqp = gdqp = NULL; - if (vap->va_mask & XFS_AT_PROJID) + if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) + prid = dp->i_d.di_projid; + else if (vap->va_mask & XFS_AT_PROJID) prid = (xfs_prid_t)vap->va_projid; else prid = (xfs_prid_t)dfltprid; -- cgit v0.10.2 From 6add2c4288801bd7fd0a4cc3277de7688f1f6714 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 21 Jun 2005 15:39:44 +1000 Subject: [XFS] Fix up some warning fallout from functions made static SGI-PV: 936255 SGI-Modid: xfs-linux:xfs-kern:193691a Signed-off-by: Eric Sandeen Signed-off-by: Nathan Scott diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 797f4d9..0cc63d6 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c @@ -93,7 +93,7 @@ xfs_btree_maxrecs( * Retrieve the block pointer from the cursor at the given level. * This may be a bmap btree root or from a buffer. */ -xfs_btree_block_t * /* generic btree block pointer */ +STATIC xfs_btree_block_t * /* generic btree block pointer */ xfs_btree_get_block( xfs_btree_cur_t *cur, /* btree cursor */ int level, /* level in btree */ diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 79918df..056f528 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c @@ -79,7 +79,7 @@ static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **lbpp, int *indexp, xfs_dabuf_t **dbpp); static void xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, int first, int last); -extern void xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp); +static void xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp); /* -- cgit v0.10.2 From 48fab6bf5f8baf0d16b20a35e537719d14b66275 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:40:20 +1000 Subject: [XFS] add XFS_INOBT_IS_FREE_DISK SGI-PV: 928382 SGI-Modid: xfs-linux:xfs-kern:193778a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h index 803c4d1..44be188 100644 --- a/fs/xfs/xfs_ialloc_btree.h +++ b/fs/xfs/xfs_ialloc_btree.h @@ -100,9 +100,13 @@ xfs_inofree_t xfs_inobt_mask(int i); #endif #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_FREE) int xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i); -#define XFS_INOBT_IS_FREE(rp,i) xfs_inobt_is_free(rp,i) +#define XFS_INOBT_IS_FREE(rp,i) xfs_inobt_is_free(rp,i) +#define XFS_INOBT_IS_FREE_DISK(rp,i) xfs_inobt_is_free_disk(rp,i) #else -#define XFS_INOBT_IS_FREE(rp,i) (((rp)->ir_free & XFS_INOBT_MASK(i)) != 0) +#define XFS_INOBT_IS_FREE(rp,i) \ + (((rp)->ir_free & XFS_INOBT_MASK(i)) != 0) +#define XFS_INOBT_IS_FREE_DISK(rp,i) \ + ((INT_GET((rp)->ir_free, ARCH_CONVERT) & XFS_INOBT_MASK(i)) != 0) #endif #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_SET_FREE) void xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i); diff --git a/fs/xfs/xfs_macros.c b/fs/xfs/xfs_macros.c index ce4f46c..698c2cd 100644 --- a/fs/xfs/xfs_macros.c +++ b/fs/xfs/xfs_macros.c @@ -1658,6 +1658,11 @@ xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i) { return XFS_INOBT_IS_FREE(rp, i); } +int +xfs_inobt_is_free_disk(xfs_inobt_rec_t *rp, int i) +{ + return XFS_INOBT_IS_FREE_DISK(rp, i); +} #endif #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_IS_LAST_REC) -- cgit v0.10.2 From f898d6c09caa40d82203acd72e9fda3cd5aeae74 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:40:48 +1000 Subject: [XFS] quiesce the filesystem proper when freezing SGI-PV: 936977 SGI-Modid: xfs-linux:xfs-kern:193840a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index d5f0340..5fe9af3 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -590,8 +590,10 @@ linvfs_sync_super( int error; int flags = SYNC_FSDATA; - if (wait) - flags |= SYNC_WAIT; + if (unlikely(sb->s_frozen == SB_FREEZE_WRITE)) + flags = SYNC_QUIESCE; + else + flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0); VFS_SYNC(vfsp, flags, NULL, error); sb->s_dirt = 0; diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h index 7649399..7ee1f71 100644 --- a/fs/xfs/linux-2.6/xfs_vfs.h +++ b/fs/xfs/linux-2.6/xfs_vfs.h @@ -107,6 +107,7 @@ typedef enum { #define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */ #define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */ #define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */ +#define SYNC_QUIESCE 0x0100 /* quiesce fileystem for a snapshot */ typedef int (*vfs_mount_t)(bhv_desc_t *, struct xfs_mount_args *, struct cred *); diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index 1035004..42bcc02 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -612,7 +612,34 @@ out: return XFS_ERROR(error); } -#define REMOUNT_READONLY_FLAGS (SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT) +STATIC int +xfs_quiesce_fs( + xfs_mount_t *mp) +{ + int count = 0, pincount; + + xfs_refcache_purge_mp(mp); + xfs_flush_buftarg(mp->m_ddev_targp, 0); + xfs_finish_reclaim_all(mp, 0); + + /* This loop must run at least twice. + * The first instance of the loop will flush + * most meta data but that will generate more + * meta data (typically directory updates). + * Which then must be flushed and logged before + * we can write the unmount record. + */ + do { + xfs_syncsub(mp, SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT, 0, NULL); + pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); + if (!pincount) { + delay(50); + count++; + } + } while (count < 2); + + return 0; +} STATIC int xfs_mntupdate( @@ -622,8 +649,7 @@ xfs_mntupdate( { struct vfs *vfsp = bhvtovfs(bdp); xfs_mount_t *mp = XFS_BHVTOM(bdp); - int pincount, error; - int count = 0; + int error; if (args->flags & XFSMNT_NOATIME) mp->m_flags |= XFS_MOUNT_NOATIME; @@ -635,25 +661,7 @@ xfs_mntupdate( } if (*flags & MS_RDONLY) { - xfs_refcache_purge_mp(mp); - xfs_flush_buftarg(mp->m_ddev_targp, 0); - xfs_finish_reclaim_all(mp, 0); - - /* This loop must run at least twice. - * The first instance of the loop will flush - * most meta data but that will generate more - * meta data (typically directory updates). - * Which then must be flushed and logged before - * we can write the unmount record. - */ - do { - VFS_SYNC(vfsp, REMOUNT_READONLY_FLAGS, NULL, error); - pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); - if (!pincount) { - delay(50); - count++; - } - } while (count < 2); + xfs_quiesce_fs(mp); /* Ok now write out an unmount record */ xfs_log_unmount_write(mp); @@ -869,10 +877,12 @@ xfs_sync( int flags, cred_t *credp) { - xfs_mount_t *mp; + xfs_mount_t *mp = XFS_BHVTOM(bdp); - mp = XFS_BHVTOM(bdp); - return (xfs_syncsub(mp, flags, 0, NULL)); + if (unlikely(flags == SYNC_QUIESCE)) + return xfs_quiesce_fs(mp); + else + return xfs_syncsub(mp, flags, 0, NULL); } /* -- cgit v0.10.2 From 7d795ca3442c7a562c45aeb7a7a808c79992a589 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:41:19 +1000 Subject: [XFS] consolidate extent item freeing SGI-PV: 938062 SGI-Modid: xfs-linux:xfs-kern:194415a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 4b45ff7..db7cbd1 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -59,6 +59,18 @@ STATIC void xfs_efi_item_abort(xfs_efi_log_item_t *); STATIC void xfs_efd_item_abort(xfs_efd_log_item_t *); +void +xfs_efi_item_free(xfs_efi_log_item_t *efip) +{ + int nexts = efip->efi_format.efi_nextents; + + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + kmem_free(efip, sizeof(xfs_efi_log_item_t) + + (nexts - 1) * sizeof(xfs_extent_t)); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } +} /* * This returns the number of iovecs needed to log the given efi item. @@ -120,8 +132,6 @@ xfs_efi_item_pin(xfs_efi_log_item_t *efip) STATIC void xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale) { - int nexts; - int size; xfs_mount_t *mp; SPLDECL(s); @@ -132,21 +142,11 @@ xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale) * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); - - nexts = efip->efi_format.efi_nextents; - if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { - size = sizeof(xfs_efi_log_item_t); - size += (nexts - 1) * sizeof(xfs_extent_t); - kmem_free(efip, size); - } else { - kmem_zone_free(xfs_efi_zone, efip); - } + xfs_efi_item_free(efip); } else { efip->efi_flags |= XFS_EFI_COMMITTED; AIL_UNLOCK(mp, s); } - - return; } /* @@ -159,8 +159,6 @@ xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale) STATIC void xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) { - int nexts; - int size; xfs_mount_t *mp; xfs_log_item_desc_t *lidp; SPLDECL(s); @@ -178,23 +176,11 @@ xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); - /* - * now free the item itself - */ - nexts = efip->efi_format.efi_nextents; - if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { - size = sizeof(xfs_efi_log_item_t); - size += (nexts - 1) * sizeof(xfs_extent_t); - kmem_free(efip, size); - } else { - kmem_zone_free(xfs_efi_zone, efip); - } + xfs_efi_item_free(efip); } else { efip->efi_flags |= XFS_EFI_COMMITTED; AIL_UNLOCK(mp, s); } - - return; } /* @@ -245,18 +231,7 @@ xfs_efi_item_committed(xfs_efi_log_item_t *efip, xfs_lsn_t lsn) STATIC void xfs_efi_item_abort(xfs_efi_log_item_t *efip) { - int nexts; - int size; - - nexts = efip->efi_format.efi_nextents; - if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { - size = sizeof(xfs_efi_log_item_t); - size += (nexts - 1) * sizeof(xfs_extent_t); - kmem_free(efip, size); - } else { - kmem_zone_free(xfs_efi_zone, efip); - } - return; + xfs_efi_item_free(efip); } /* @@ -355,8 +330,6 @@ xfs_efi_release(xfs_efi_log_item_t *efip, { xfs_mount_t *mp; int extents_left; - uint size; - int nexts; SPLDECL(s); mp = efip->efi_item.li_mountp; @@ -372,20 +345,10 @@ xfs_efi_release(xfs_efi_log_item_t *efip, * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); + xfs_efi_item_free(efip); } else { AIL_UNLOCK(mp, s); } - - if (extents_left == 0) { - nexts = efip->efi_format.efi_nextents; - if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { - size = sizeof(xfs_efi_log_item_t); - size += (nexts - 1) * sizeof(xfs_extent_t); - kmem_free(efip, size); - } else { - kmem_zone_free(xfs_efi_zone, efip); - } - } } /* @@ -398,8 +361,6 @@ STATIC void xfs_efi_cancel( xfs_efi_log_item_t *efip) { - int nexts; - int size; xfs_mount_t *mp; SPLDECL(s); @@ -410,26 +371,25 @@ xfs_efi_cancel( * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); - - nexts = efip->efi_format.efi_nextents; - if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { - size = sizeof(xfs_efi_log_item_t); - size += (nexts - 1) * sizeof(xfs_extent_t); - kmem_free(efip, size); - } else { - kmem_zone_free(xfs_efi_zone, efip); - } + xfs_efi_item_free(efip); } else { efip->efi_flags |= XFS_EFI_CANCELED; AIL_UNLOCK(mp, s); } - - return; } +STATIC void +xfs_efd_item_free(xfs_efd_log_item_t *efdp) +{ + int nexts = efdp->efd_format.efd_nextents; - - + if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { + kmem_free(efdp, sizeof(xfs_efd_log_item_t) + + (nexts - 1) * sizeof(xfs_extent_t)); + } else { + kmem_zone_free(xfs_efd_zone, efdp); + } +} /* * This returns the number of iovecs needed to log the given efd item. @@ -533,9 +493,6 @@ xfs_efd_item_unlock(xfs_efd_log_item_t *efdp) STATIC xfs_lsn_t xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn) { - uint size; - int nexts; - /* * If we got a log I/O error, it's always the case that the LR with the * EFI got unpinned and freed before the EFD got aborted. @@ -543,15 +500,7 @@ xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn) if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0) xfs_efi_release(efdp->efd_efip, efdp->efd_format.efd_nextents); - nexts = efdp->efd_format.efd_nextents; - if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { - size = sizeof(xfs_efd_log_item_t); - size += (nexts - 1) * sizeof(xfs_extent_t); - kmem_free(efdp, size); - } else { - kmem_zone_free(xfs_efd_zone, efdp); - } - + xfs_efd_item_free(efdp); return (xfs_lsn_t)-1; } @@ -565,9 +514,6 @@ xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn) STATIC void xfs_efd_item_abort(xfs_efd_log_item_t *efdp) { - int nexts; - int size; - /* * If we got a log I/O error, it's always the case that the LR with the * EFI got unpinned and freed before the EFD got aborted. So don't @@ -576,15 +522,7 @@ xfs_efd_item_abort(xfs_efd_log_item_t *efdp) if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0) xfs_efi_cancel(efdp->efd_efip); - nexts = efdp->efd_format.efd_nextents; - if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { - size = sizeof(xfs_efd_log_item_t); - size += (nexts - 1) * sizeof(xfs_extent_t); - kmem_free(efdp, size); - } else { - kmem_zone_free(xfs_efd_zone, efdp); - } - return; + xfs_efd_item_free(efdp); } /* diff --git a/fs/xfs/xfs_extfree_item.h b/fs/xfs/xfs_extfree_item.h index 7122d61..d433bac 100644 --- a/fs/xfs/xfs_extfree_item.h +++ b/fs/xfs/xfs_extfree_item.h @@ -118,6 +118,8 @@ xfs_efi_log_item_t *xfs_efi_init(struct xfs_mount *, uint); xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *, uint); +void xfs_efi_item_free(xfs_efi_log_item_t *); + #endif /* __KERNEL__ */ #endif /* __XFS_EXTFREE_ITEM_H__ */ diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 91d764a..0aac28d 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -2747,7 +2747,6 @@ xlog_recover_do_efd_trans( xfs_efi_log_item_t *efip = NULL; xfs_log_item_t *lip; int gen; - int nexts; __uint64_t efi_id; SPLDECL(s); @@ -2782,22 +2781,15 @@ xlog_recover_do_efd_trans( } lip = xfs_trans_next_ail(mp, lip, &gen, NULL); } - if (lip == NULL) { - AIL_UNLOCK(mp, s); - } /* * If we found it, then free it up. If it wasn't there, it * must have been overwritten in the log. Oh well. */ if (lip != NULL) { - nexts = efip->efi_format.efi_nextents; - if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { - kmem_free(lip, sizeof(xfs_efi_log_item_t) + - ((nexts - 1) * sizeof(xfs_extent_t))); - } else { - kmem_zone_free(xfs_efi_zone, efip); - } + xfs_efi_item_free(efip); + } else { + AIL_UNLOCK(mp, s); } } -- cgit v0.10.2 From d130c14c0310edac5ea0c6327bef7e3715f9a083 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:43:22 +1000 Subject: [XFS] simplify ASSERT SGI-PV: 938063 SGI-Modid: xfs-linux:xfs-kern:194416a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c index 7d6e1f3..4ed7b69 100644 --- a/fs/xfs/support/debug.c +++ b/fs/xfs/support/debug.c @@ -36,7 +36,6 @@ #include #include -int doass = 1; static char message[256]; /* keep it off the stack */ static DEFINE_SPINLOCK(xfs_err_lock); diff --git a/fs/xfs/support/debug.h b/fs/xfs/support/debug.h index 40b0f4c..c5b9365 100644 --- a/fs/xfs/support/debug.h +++ b/fs/xfs/support/debug.h @@ -50,16 +50,11 @@ extern void cmn_err(int, char *, ...); #endif #ifdef DEBUG -# ifdef lint -# define ASSERT(EX) ((void)0) /* avoid "constant in conditional" babble */ -# else -# define ASSERT(EX) ((!doass||(EX))?((void)0):assfail(#EX, __FILE__, __LINE__)) -# endif /* lint */ +# define ASSERT(EX) ((EX) ? ((void)0) : assfail(#EX, __FILE__, __LINE__)) #else # define ASSERT(x) ((void)0) #endif -extern int doass; /* dynamically turn off asserts */ extern void assfail(char *, char *, int); #ifdef DEBUG extern unsigned long random(void); -- cgit v0.10.2 From bd5a876ac4c130e8e1986dcdbb21839ae4cd91c0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2005 15:47:39 +1000 Subject: [XFS] (mostly) remove xfs_inval_cached_pages Since the last round of direct I/O locking changes it is just a wrapper around VOP_FLUSHINVAL_PAGES, so it's not nessecary anymore. Keep a simplified version for kernels < 2.4.22, as these don't have the changed direct I/O locking. SGI-PV: 938064 SGI-Modid: xfs-linux:xfs-kern:194420a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index aa9daae..46b61a8 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -209,30 +209,6 @@ unlock: return (-status); } -/* - * xfs_inval_cached_pages - * - * This routine is responsible for keeping direct I/O and buffered I/O - * somewhat coherent. From here we make sure that we're at least - * temporarily holding the inode I/O lock exclusively and then call - * the page cache to flush and invalidate any cached pages. If there - * are no cached pages this routine will be very quick. - */ -void -xfs_inval_cached_pages( - vnode_t *vp, - xfs_iocore_t *io, - xfs_off_t offset, - int write, - int relock) -{ - if (VN_CACHED(vp)) { - xfs_inval_cached_trace(io, offset, -1, ctooff(offtoct(offset)), -1); - VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(offset)), -1, FI_REMAPF_LOCKED); - } - -} - ssize_t /* bytes read, or (-) error */ xfs_read( bhv_desc_t *bdp, diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index d723e35..f197a72 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h @@ -94,8 +94,6 @@ extern int xfs_bdstrat_cb(struct xfs_buf *); extern int xfs_zero_eof(struct vnode *, struct xfs_iocore *, xfs_off_t, xfs_fsize_t, xfs_fsize_t); -extern void xfs_inval_cached_pages(struct vnode *, struct xfs_iocore *, - xfs_off_t, int, int); extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *, const struct iovec *, unsigned int, loff_t *, int, struct cred *); diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 63abdc2..681be5c 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -180,9 +180,10 @@ xfs_swapext( goto error0; } - if (VN_CACHED(tvp) != 0) - xfs_inval_cached_pages(XFS_ITOV(tip), &(tip->i_iocore), - (xfs_off_t)0, 0, 0); + if (VN_CACHED(tvp) != 0) { + xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1); + VOP_FLUSHINVAL_PAGES(tvp, 0, -1, FI_REMAPF_LOCKED); + } /* Verify O_DIRECT for ftmp */ if (VN_CACHED(tvp) != 0) { diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 96dc18b..d64ebcf 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -4329,6 +4329,7 @@ xfs_free_file_space( xfs_off_t len, int attr_flags) { + vnode_t *vp; int committed; int done; xfs_off_t end_dmi_offset; @@ -4349,9 +4350,11 @@ xfs_free_file_space( xfs_trans_t *tp; int need_iolock = 1; - vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address); + vp = XFS_ITOV(ip); mp = ip->i_mount; + vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); + if ((error = XFS_QM_DQATTACH(mp, ip, 0))) return error; @@ -4368,7 +4371,7 @@ xfs_free_file_space( DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) { if (end_dmi_offset > ip->i_d.di_size) end_dmi_offset = ip->i_d.di_size; - error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOV(ip), + error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, vp, offset, end_dmi_offset - offset, AT_DELAY_FLAG(attr_flags), NULL); if (error) @@ -4387,7 +4390,14 @@ xfs_free_file_space( ioffset = offset & ~(rounding - 1); if (ilen & (rounding - 1)) ilen = (ilen + rounding) & ~(rounding - 1); - xfs_inval_cached_pages(XFS_ITOV(ip), &(ip->i_iocore), ioffset, 0, 0); + + if (VN_CACHED(vp) != 0) { + xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1, + ctooff(offtoct(ioffset)), -1); + VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(ioffset)), + -1, FI_REMAPF_LOCKED); + } + /* * Need to zero the stuff we're not freeing, on disk. * If its a realtime file & can't use unwritten extents then we -- cgit v0.10.2 From 77bc5beb5977a166e41b87c9d55d8e9cf2b3a04f Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Tue, 21 Jun 2005 15:48:04 +1000 Subject: [XFS] Makes more sense to use the fsxattr interface instead of adding new ioctls for project IDs. SGI-PV: 938145 SGI-Modid: xfs-linux:xfs-kern:22899a Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index df17d93..05a447e 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -777,8 +777,6 @@ xfs_ioctl( case XFS_IOC_GETVERSION: case XFS_IOC_GETXFLAGS: case XFS_IOC_SETXFLAGS: - case XFS_IOC_GETPROJID: - case XFS_IOC_SETPROJID: case XFS_IOC_FSGETXATTR: case XFS_IOC_FSSETXATTR: case XFS_IOC_FSGETXATTRA: @@ -1176,7 +1174,8 @@ xfs_ioc_xattr( switch (cmd) { case XFS_IOC_FSGETXATTR: { - va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS; + va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ + XFS_AT_NEXTENTS | XFS_AT_PROJID; VOP_GETATTR(vp, &va, 0, NULL, error); if (error) return -error; @@ -1184,6 +1183,7 @@ xfs_ioc_xattr( fa.fsx_xflags = va.va_xflags; fa.fsx_extsize = va.va_extsize; fa.fsx_nextents = va.va_nextents; + fa.fsx_projid = va.va_projid; if (copy_to_user(arg, &fa, sizeof(fa))) return -XFS_ERROR(EFAULT); @@ -1198,9 +1198,10 @@ xfs_ioc_xattr( if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) attr_flags |= ATTR_NONBLOCK; - va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE; + va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID; va.va_xflags = fa.fsx_xflags; va.va_extsize = fa.fsx_extsize; + va.va_projid = fa.fsx_projid; VOP_SETATTR(vp, &va, attr_flags, NULL, error); if (!error) @@ -1209,7 +1210,8 @@ xfs_ioc_xattr( } case XFS_IOC_FSGETXATTRA: { - va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS; + va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ + XFS_AT_ANEXTENTS | XFS_AT_PROJID; VOP_GETATTR(vp, &va, 0, NULL, error); if (error) return -error; @@ -1217,6 +1219,7 @@ xfs_ioc_xattr( fa.fsx_xflags = va.va_xflags; fa.fsx_extsize = va.va_extsize; fa.fsx_nextents = va.va_anextents; + fa.fsx_projid = va.va_projid; if (copy_to_user(arg, &fa, sizeof(fa))) return -XFS_ERROR(EFAULT); @@ -1260,26 +1263,6 @@ xfs_ioc_xattr( return 0; } - case XFS_IOC_GETPROJID: { - va.va_mask = XFS_AT_PROJID; - VOP_GETATTR(vp, &va, 0, NULL, error); - if (error) - return -error; - if (copy_to_user(arg, &va.va_projid, sizeof(va.va_projid))) - return -XFS_ERROR(EFAULT); - return 0; - } - - case XFS_IOC_SETPROJID: { - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - va.va_mask = XFS_AT_PROJID; - if (copy_from_user(&va.va_projid, arg, sizeof(va.va_projid))) - return -XFS_ERROR(EFAULT); - VOP_SETATTR(vp, &va, 0, NULL, error); - return -error; - } - default: return -ENOTTY; } diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index be72aca..0f8f138 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -100,8 +100,6 @@ __linvfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg) case XFS_IOC_GETBMAP: case XFS_IOC_GETBMAPA: case XFS_IOC_GETBMAPX: - case XFS_IOC_SETPROJID: - case XFS_IOC_GETPROJID: /* not handled case XFS_IOC_FD_TO_HANDLE: case XFS_IOC_PATH_TO_HANDLE: diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index a7bd468..095af0a 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h @@ -60,7 +60,8 @@ struct fsxattr { __u32 fsx_xflags; /* xflags field value (get/set) */ __u32 fsx_extsize; /* extsize field value (get/set)*/ __u32 fsx_nextents; /* nextents field value (get) */ - unsigned char fsx_pad[16]; + __u32 fsx_projid; /* project identifier (get/set) */ + unsigned char fsx_pad[12]; }; #endif @@ -477,8 +478,6 @@ typedef struct xfs_handle { /* XFS_IOC_SETBIOSIZE ---- deprecated 46 */ /* XFS_IOC_GETBIOSIZE ---- deprecated 47 */ #define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) -#define XFS_IOC_SETPROJID _IOWR('X', 57, __uint32_t) -#define XFS_IOC_GETPROJID _IOWR('X', 58, __uint32_t) /* * ioctl commands that replace IRIX syssgi()'s -- cgit v0.10.2 From 06d10dd9ca70ff1318ff2b871ff5f61a94223d9f Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Tue, 21 Jun 2005 15:48:47 +1000 Subject: [XFS] Merge fixes into realtime quota code, since one/two reported, still not enabled though. SGI-PV: 938145 SGI-Modid: xfs-linux:xfs-kern:22900a Signed-off-by: Nathan Scott diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 3ea7597..3254cb7 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -1251,6 +1251,10 @@ xfs_qm_init_quotainfo( INT_GET(ddqp->d_iwarns, ARCH_CONVERT) ? INT_GET(ddqp->d_iwarns, ARCH_CONVERT) : XFS_QM_IWARNLIMIT; + qinf->qi_rtbwarnlimit = + INT_GET(ddqp->d_rtbwarns, ARCH_CONVERT) ? + INT_GET(ddqp->d_rtbwarns, ARCH_CONVERT) : + XFS_QM_RTBWARNLIMIT; qinf->qi_bhardlimit = INT_GET(ddqp->d_blk_hardlimit, ARCH_CONVERT); qinf->qi_bsoftlimit = @@ -1276,6 +1280,7 @@ xfs_qm_init_quotainfo( qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT; qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT; qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT; + qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT; } return (0); @@ -2624,6 +2629,9 @@ xfs_qm_vop_chown( xfs_dquot_t *newdq) { xfs_dquot_t *prevdq; + uint bfield = XFS_IS_REALTIME_INODE(ip) ? + XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT; + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount)); @@ -2632,20 +2640,12 @@ xfs_qm_vop_chown( ASSERT(prevdq); ASSERT(prevdq != newdq); - xfs_trans_mod_dquot(tp, prevdq, - XFS_TRANS_DQ_BCOUNT, - -(ip->i_d.di_nblocks)); - xfs_trans_mod_dquot(tp, prevdq, - XFS_TRANS_DQ_ICOUNT, - -1); + xfs_trans_mod_dquot(tp, prevdq, bfield, -(ip->i_d.di_nblocks)); + xfs_trans_mod_dquot(tp, prevdq, XFS_TRANS_DQ_ICOUNT, -1); /* the sparkling new dquot */ - xfs_trans_mod_dquot(tp, newdq, - XFS_TRANS_DQ_BCOUNT, - ip->i_d.di_nblocks); - xfs_trans_mod_dquot(tp, newdq, - XFS_TRANS_DQ_ICOUNT, - 1); + xfs_trans_mod_dquot(tp, newdq, bfield, ip->i_d.di_nblocks); + xfs_trans_mod_dquot(tp, newdq, XFS_TRANS_DQ_ICOUNT, 1); /* * Take an extra reference, because the inode @@ -2673,7 +2673,7 @@ xfs_qm_vop_chown_reserve( { int error; xfs_mount_t *mp; - uint delblks; + uint delblks, blkflags; xfs_dquot_t *unresudq, *unresgdq, *delblksudq, *delblksgdq; ASSERT(XFS_ISLOCKED_INODE(ip)); @@ -2682,6 +2682,8 @@ xfs_qm_vop_chown_reserve( delblks = ip->i_delayed_blks; delblksudq = delblksgdq = unresudq = unresgdq = NULL; + blkflags = XFS_IS_REALTIME_INODE(ip) ? + XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS; if (XFS_IS_UQUOTA_ON(mp) && udqp && ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) { @@ -2711,7 +2713,7 @@ xfs_qm_vop_chown_reserve( if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount, delblksudq, delblksgdq, ip->i_d.di_nblocks, 1, - flags | XFS_QMOPT_RES_REGBLKS))) + flags | blkflags))) return (error); /* @@ -2728,11 +2730,11 @@ xfs_qm_vop_chown_reserve( ASSERT(unresudq || unresgdq); if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount, delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0, - flags | XFS_QMOPT_RES_REGBLKS))) + flags | blkflags))) return (error); xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount, unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0, - XFS_QMOPT_RES_REGBLKS); + blkflags); } return (0); diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h index 7819687..b03eecf 100644 --- a/fs/xfs/quota/xfs_qm.h +++ b/fs/xfs/quota/xfs_qm.h @@ -133,8 +133,9 @@ typedef struct xfs_quotainfo { time_t qi_btimelimit; /* limit for blks timer */ time_t qi_itimelimit; /* limit for inodes timer */ time_t qi_rtbtimelimit;/* limit for rt blks timer */ - xfs_qwarncnt_t qi_bwarnlimit; /* limit for num warnings */ - xfs_qwarncnt_t qi_iwarnlimit; /* limit for num warnings */ + xfs_qwarncnt_t qi_bwarnlimit; /* limit for blks warnings */ + xfs_qwarncnt_t qi_iwarnlimit; /* limit for inodes warnings */ + xfs_qwarncnt_t qi_rtbwarnlimit;/* limit for rt blks warnings */ mutex_t qi_quotaofflock;/* to serialize quotaoff */ xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */ uint qi_dqperchunk; /* # ondisk dqs in above chunk */ @@ -176,6 +177,7 @@ typedef struct xfs_dquot_acct { #define XFS_QM_BWARNLIMIT 5 #define XFS_QM_IWARNLIMIT 5 +#define XFS_QM_RTBWARNLIMIT 5 #define XFS_QM_LOCK(xqm) (mutex_lock(&xqm##_lock, PINOD)) #define XFS_QM_UNLOCK(xqm) (mutex_unlock(&xqm##_lock)) diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h index 472afd3..bf413e7 100644 --- a/fs/xfs/quota/xfs_quota_priv.h +++ b/fs/xfs/quota/xfs_quota_priv.h @@ -56,6 +56,7 @@ #define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit) #define XFS_QI_ITIMELIMIT(mp) ((mp)->m_quotainfo->qi_itimelimit) #define XFS_QI_BWARNLIMIT(mp) ((mp)->m_quotainfo->qi_bwarnlimit) +#define XFS_QI_RTBWARNLIMIT(mp) ((mp)->m_quotainfo->qi_rtbwarnlimit) #define XFS_QI_IWARNLIMIT(mp) ((mp)->m_quotainfo->qi_iwarnlimit) #define XFS_QI_QOFFLOCK(mp) ((mp)->m_quotainfo->qi_quotaofflock) diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c index 565efb7..3b99daf 100644 --- a/fs/xfs/quota/xfs_trans_dquot.c +++ b/fs/xfs/quota/xfs_trans_dquot.c @@ -497,7 +497,7 @@ xfs_trans_apply_dquot_deltas( * Adjust the RT reservation. */ if (qtrx->qt_rtblk_res != 0) { - if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) { + if (qtrx->qt_rtblk_res != qtrx->qt_rtblk_res_used) { if (qtrx->qt_rtblk_res > qtrx->qt_rtblk_res_used) dqp->q_res_rtbcount -= (xfs_qcnt_t) @@ -530,12 +530,6 @@ xfs_trans_apply_dquot_deltas( (xfs_qcnt_t)qtrx->qt_icount_delta; } - -#ifdef QUOTADEBUG - if (qtrx->qt_rtblk_res != 0) - cmn_err(CE_DEBUG, "RT res %d for 0x%p\n", - (int) qtrx->qt_rtblk_res, dqp); -#endif ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); ASSERT(dqp->q_res_icount >= @@ -636,7 +630,10 @@ xfs_trans_dqresv( int error; xfs_qcnt_t hardlimit; xfs_qcnt_t softlimit; - time_t btimer; + time_t timer; + xfs_qwarncnt_t warns; + xfs_qwarncnt_t warnlimit; + xfs_qcnt_t count; xfs_qcnt_t *resbcountp; xfs_quotainfo_t *q = mp->m_quotainfo; @@ -651,7 +648,9 @@ xfs_trans_dqresv( softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT); if (!softlimit) softlimit = q->qi_bsoftlimit; - btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT); + timer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT); + warns = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT); + warnlimit = XFS_QI_BWARNLIMIT(dqp->q_mount); resbcountp = &dqp->q_res_bcount; } else { ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS); @@ -661,7 +660,9 @@ xfs_trans_dqresv( softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT); if (!softlimit) softlimit = q->qi_rtbsoftlimit; - btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT); + timer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT); + warns = INT_GET(dqp->q_core.d_rtbwarns, ARCH_CONVERT); + warnlimit = XFS_QI_RTBWARNLIMIT(dqp->q_mount); resbcountp = &dqp->q_res_rtbcount; } error = 0; @@ -691,37 +692,36 @@ xfs_trans_dqresv( * If timer or warnings has expired, * return EDQUOT */ - if ((btimer != 0 && get_seconds() > btimer) || - (dqp->q_core.d_bwarns && - INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >= - XFS_QI_BWARNLIMIT(dqp->q_mount))) { + if ((timer != 0 && get_seconds() > timer) || + (warns != 0 && warns >= warnlimit)) { error = EDQUOT; goto error_return; } } } if (ninos > 0) { - hardlimit = INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT); + count = INT_GET(dqp->q_core.d_icount, ARCH_CONVERT); + timer = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT); + warns = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT); + warnlimit = XFS_QI_IWARNLIMIT(dqp->q_mount); + hardlimit = INT_GET(dqp->q_core.d_ino_hardlimit, + ARCH_CONVERT); if (!hardlimit) hardlimit = q->qi_ihardlimit; - softlimit = INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT); + softlimit = INT_GET(dqp->q_core.d_ino_softlimit, + ARCH_CONVERT); if (!softlimit) softlimit = q->qi_isoftlimit; - if (hardlimit > 0ULL && - INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= hardlimit) { + if (hardlimit > 0ULL && count >= hardlimit) { error = EDQUOT; goto error_return; - } else if (softlimit > 0ULL && - INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= softlimit) { + } else if (softlimit > 0ULL && count >= softlimit) { /* * If timer or warnings has expired, * return EDQUOT */ - if ((dqp->q_core.d_itimer && - get_seconds() > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) || - (dqp->q_core.d_iwarns && - INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >= - XFS_QI_IWARNLIMIT(dqp->q_mount))) { + if ((timer != 0 && get_seconds() > timer) || + (warns != 0 && warns >= warnlimit)) { error = EDQUOT; goto error_return; } diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index f6f5ad3..6f5d283 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -4545,18 +4545,17 @@ xfs_bmapi( xfs_extlen_t alen; /* allocated extent length */ xfs_fileoff_t aoff; /* allocated file offset */ xfs_bmalloca_t bma; /* args for xfs_bmap_alloc */ - char contig; /* allocation must be one extent */ xfs_btree_cur_t *cur; /* bmap btree cursor */ - char delay; /* this request is for delayed alloc */ xfs_fileoff_t end; /* end of mapped file region */ int eof; /* we've hit the end of extent list */ + char contig; /* allocation must be one extent */ + char delay; /* this request is for delayed alloc */ + char exact; /* don't do all of wasdelayed extent */ xfs_bmbt_rec_t *ep; /* extent list entry pointer */ int error; /* error return */ - char exact; /* don't do all of wasdelayed extent */ xfs_bmbt_irec_t got; /* current extent list record */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_extlen_t indlen; /* indirect blocks length */ - char inhole; /* current location is hole in file */ xfs_extnum_t lastx; /* last useful extent number */ int logflags; /* flags for transaction logging */ xfs_extlen_t minleft; /* min blocks left after allocation */ @@ -4567,13 +4566,15 @@ xfs_bmapi( xfs_extnum_t nextents; /* number of extents in file */ xfs_fileoff_t obno; /* old block number (offset) */ xfs_bmbt_irec_t prev; /* previous extent list record */ - char stateless; /* ignore state flag set */ int tmp_logflags; /* temp flags holder */ + int whichfork; /* data or attr fork */ + char inhole; /* current location is hole in file */ + char stateless; /* ignore state flag set */ char trim; /* output trimmed to match range */ char userdata; /* allocating non-metadata */ char wasdelay; /* old extent was delayed */ - int whichfork; /* data or attr fork */ char wr; /* this is a write request */ + char rt; /* this is a realtime file */ char rsvd; /* OK to allocate reserved blocks */ #ifdef DEBUG xfs_fileoff_t orig_bno; /* original block number value */ @@ -4603,6 +4604,7 @@ xfs_bmapi( } if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); + rt = XFS_IS_REALTIME_INODE(ip); ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(ifp->if_ext_max == XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); @@ -4707,9 +4709,16 @@ xfs_bmapi( } minlen = contig ? alen : 1; if (delay) { - indlen = (xfs_extlen_t) - xfs_bmap_worst_indlen(ip, alen); - ASSERT(indlen > 0); + xfs_extlen_t extsz = 0; + + /* Figure out the extent size, adjust alen */ + if (rt) { + if (!(extsz = ip->i_d.di_extsize)) + extsz = mp->m_sb.sb_rextsize; + alen = roundup(alen, extsz); + extsz = alen / mp->m_sb.sb_rextsize; + } + /* * Make a transaction-less quota reservation for * delayed allocation blocks. This number gets @@ -4717,8 +4726,10 @@ xfs_bmapi( * We return EDQUOT if we haven't allocated * blks already inside this loop; */ - if (XFS_TRANS_RESERVE_BLKQUOTA( - mp, NULL, ip, (long)alen)) { + if (XFS_TRANS_RESERVE_QUOTA_NBLKS( + mp, NULL, ip, (long)alen, 0, + rt ? XFS_QMOPT_RES_RTBLKS : + XFS_QMOPT_RES_REGBLKS)) { if (n == 0) { *nmap = 0; ASSERT(cur == NULL); @@ -4731,40 +4742,34 @@ xfs_bmapi( * Split changing sb for alen and indlen since * they could be coming from different places. */ - if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { - xfs_extlen_t extsz; - xfs_extlen_t ralen; - if (!(extsz = ip->i_d.di_extsize)) - extsz = mp->m_sb.sb_rextsize; - ralen = roundup(alen, extsz); - ralen = ralen / mp->m_sb.sb_rextsize; - if (xfs_mod_incore_sb(mp, - XFS_SBS_FREXTENTS, - -(ralen), rsvd)) { - if (XFS_IS_QUOTA_ON(ip->i_mount)) - XFS_TRANS_UNRESERVE_BLKQUOTA( - mp, NULL, ip, - (long)alen); - break; - } - } else { - if (xfs_mod_incore_sb(mp, - XFS_SBS_FDBLOCKS, - -(alen), rsvd)) { - if (XFS_IS_QUOTA_ON(ip->i_mount)) - XFS_TRANS_UNRESERVE_BLKQUOTA( - mp, NULL, ip, - (long)alen); - break; - } - } + indlen = (xfs_extlen_t) + xfs_bmap_worst_indlen(ip, alen); + ASSERT(indlen > 0); - if (xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, - -(indlen), rsvd)) { - XFS_TRANS_UNRESERVE_BLKQUOTA( - mp, NULL, ip, (long)alen); + if (rt) + error = xfs_mod_incore_sb(mp, + XFS_SBS_FREXTENTS, + -(extsz), rsvd); + else + error = xfs_mod_incore_sb(mp, + XFS_SBS_FDBLOCKS, + -(alen), rsvd); + if (!error) + error = xfs_mod_incore_sb(mp, + XFS_SBS_FDBLOCKS, + -(indlen), rsvd); + + if (error) { + if (XFS_IS_QUOTA_ON(ip->i_mount)) + /* unreserve the blocks now */ + XFS_TRANS_UNRESERVE_QUOTA_NBLKS( + mp, NULL, ip, + (long)alen, 0, rt ? + XFS_QMOPT_RES_RTBLKS : + XFS_QMOPT_RES_REGBLKS); break; } + ip->i_delayed_blks += alen; abno = NULLSTARTBLOCK(indlen); } else { @@ -5389,13 +5394,24 @@ xfs_bunmapi( } if (wasdel) { ASSERT(STARTBLOCKVAL(del.br_startblock) > 0); - xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, - (int)del.br_blockcount, rsvd); - /* Unreserve our quota space */ - XFS_TRANS_RESERVE_QUOTA_NBLKS( - mp, NULL, ip, -((long)del.br_blockcount), 0, - isrt ? XFS_QMOPT_RES_RTBLKS : + /* Update realtim/data freespace, unreserve quota */ + if (isrt) { + xfs_filblks_t rtexts; + + rtexts = XFS_FSB_TO_B(mp, del.br_blockcount); + do_div(rtexts, mp->m_sb.sb_rextsize); + xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, + (int)rtexts, rsvd); + XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip, + -((long)del.br_blockcount), 0, + XFS_QMOPT_RES_RTBLKS); + } else { + xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, + (int)del.br_blockcount, rsvd); + XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip, + -((long)del.br_blockcount), 0, XFS_QMOPT_RES_REGBLKS); + } ip->i_delayed_blks -= del.br_blockcount; if (cur) cur->bc_private.b.flags |= diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 469e1a7..2edd676 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -385,15 +385,15 @@ xfs_iomap_write_direct( int nimaps, maps; int error; int bmapi_flag; + int quota_flag; int rt; xfs_trans_t *tp; xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp; xfs_bmap_free_t free_list; int aeof; - xfs_filblks_t datablocks; + xfs_filblks_t datablocks, qblocks, resblks; int committed; int numrtextents; - uint resblks; /* * Make sure that the dquots are there. This doesn't hold @@ -419,7 +419,6 @@ xfs_iomap_write_direct( xfs_fileoff_t map_last_fsb; map_last_fsb = ret_imap->br_blockcount + ret_imap->br_startoff; - if (map_last_fsb < last_fsb) { last_fsb = map_last_fsb; count_fsb = last_fsb - offset_fsb; @@ -428,56 +427,47 @@ xfs_iomap_write_direct( } /* - * determine if reserving space on - * the data or realtime partition. + * Determine if reserving space on the data or realtime partition. */ if ((rt = XFS_IS_REALTIME_INODE(ip))) { - int sbrtextsize, iprtextsize; + xfs_extlen_t extsz; - sbrtextsize = mp->m_sb.sb_rextsize; - iprtextsize = - ip->i_d.di_extsize ? ip->i_d.di_extsize : sbrtextsize; - numrtextents = (count_fsb + iprtextsize - 1); - do_div(numrtextents, sbrtextsize); + if (!(extsz = ip->i_d.di_extsize)) + extsz = mp->m_sb.sb_rextsize; + numrtextents = qblocks = (count_fsb + extsz - 1); + do_div(numrtextents, mp->m_sb.sb_rextsize); + quota_flag = XFS_QMOPT_RES_RTBLKS; datablocks = 0; } else { - datablocks = count_fsb; + datablocks = qblocks = count_fsb; + quota_flag = XFS_QMOPT_RES_REGBLKS; numrtextents = 0; } /* - * allocate and setup the transaction + * Allocate and setup the transaction */ xfs_iunlock(ip, XFS_ILOCK_EXCL); tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); - resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks); - error = xfs_trans_reserve(tp, resblks, XFS_WRITE_LOG_RES(mp), numrtextents, XFS_TRANS_PERM_LOG_RES, XFS_WRITE_LOG_COUNT); /* - * check for running out of space + * Check for running out of space, note: need lock to return */ if (error) - /* - * Free the transaction structure. - */ xfs_trans_cancel(tp, 0); - xfs_ilock(ip, XFS_ILOCK_EXCL); - if (error) - goto error_out; /* Don't return in above if .. trans .., - need lock to return */ + goto error_out; - if (XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, resblks)) { + if (XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag)) { error = (EDQUOT); goto error1; } - nimaps = 1; bmapi_flag = XFS_BMAPI_WRITE; xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); @@ -487,31 +477,29 @@ xfs_iomap_write_direct( bmapi_flag |= XFS_BMAPI_PREALLOC; /* - * issue the bmapi() call to allocate the blocks + * Issue the bmapi() call to allocate the blocks */ XFS_BMAP_INIT(&free_list, &firstfsb); + nimaps = 1; imapp = &imap[0]; error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, bmapi_flag, &firstfsb, 0, imapp, &nimaps, &free_list); - if (error) { + if (error) goto error0; - } /* - * complete the transaction + * Complete the transaction */ - error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); - if (error) { + if (error) goto error0; - } - error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); - if (error) { + if (error) goto error_out; - } - /* copy any maps to caller's array and return any error. */ + /* + * Copy any maps to caller's array and return any error. + */ if (nimaps == 0) { error = (ENOSPC); goto error_out; @@ -530,10 +518,11 @@ xfs_iomap_write_direct( } return 0; - error0: /* Cancel bmap, unlock inode, and cancel trans */ +error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */ xfs_bmap_cancel(&free_list); + XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag); - error1: /* Just cancel transaction */ +error1: /* Just cancel transaction */ xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); *nmaps = 0; /* nothing set-up here */ diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index 341cb46..7134576 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h @@ -352,15 +352,8 @@ typedef struct xfs_dqtrxops { #define XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp) \ XFS_DQTRXOP_VOID(mp, tp, qo_unreserve_and_mod_dquots) -#define XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, nblks) \ - XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \ - XFS_QMOPT_RES_REGBLKS) -#define XFS_TRANS_RESERVE_BLKQUOTA_FORCE(mp, tp, ip, nblks) \ - XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \ - XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES) -#define XFS_TRANS_UNRESERVE_BLKQUOTA(mp, tp, ip, nblks) \ - XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, -(nblks), 0, \ - XFS_QMOPT_RES_REGBLKS) +#define XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, ninos, flags) \ + XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, -(nblks), -(ninos), flags) #define XFS_TRANS_RESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \ XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, \ f | XFS_QMOPT_RES_REGBLKS) diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index d64ebcf..1377c86 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -4175,9 +4175,8 @@ retry: break; } xfs_ilock(ip, XFS_ILOCK_EXCL); - error = XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, - ip->i_udquot, ip->i_gdquot, resblks, 0, rt ? - XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS); + error = XFS_TRANS_RESERVE_QUOTA(mp, tp, + ip->i_udquot, ip->i_gdquot, resblks, 0, 0); if (error) goto error1; -- cgit v0.10.2 From 754002b4fb1b553bd8f978bb6f5aca7af46fde67 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Tue, 21 Jun 2005 15:49:06 +1000 Subject: [XFS] Merge a few minor fixes to the quota warning code. SGI-PV: 938145 SGI-Modid: xfs-linux:xfs-kern:22901a Signed-off-by: Nathan Scott diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index 68089f5..32ec7f4 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -286,7 +286,9 @@ xfs_qm_adjust_dqlimits( * We also return 0 as the values of the timers in Q_GETQUOTA calls, when * enforcement's off. * In contrast, warnings are a little different in that they don't - * 'automatically' get started when limits get exceeded. + * 'automatically' get started when limits get exceeded. They do + * get reset to zero, however, when we find the count to be under + * the soft limit (they are only ever set non-zero via userspace). */ void xfs_qm_adjust_dqtimers( @@ -315,6 +317,8 @@ xfs_qm_adjust_dqtimers( INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { INT_SET(d->d_btimer, ARCH_CONVERT, get_seconds() + XFS_QI_BTIMELIMIT(mp)); + } else { + d->d_bwarns = 0; } } else { if ((!d->d_blk_softlimit || @@ -336,6 +340,8 @@ xfs_qm_adjust_dqtimers( INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { INT_SET(d->d_itimer, ARCH_CONVERT, get_seconds() + XFS_QI_ITIMELIMIT(mp)); + } else { + d->d_iwarns = 0; } } else { if ((!d->d_ino_softlimit || @@ -357,6 +363,8 @@ xfs_qm_adjust_dqtimers( INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) { INT_SET(d->d_rtbtimer, ARCH_CONVERT, get_seconds() + XFS_QI_RTBTIMELIMIT(mp)); + } else { + d->d_rtbwarns = 0; } } else { if ((!d->d_rtb_softlimit || diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 3254cb7..f665ca8f 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -1550,8 +1550,10 @@ xfs_qm_reset_dqcounts( INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL); INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0); INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0); + INT_SET(ddq->d_rtbtimer, ARCH_CONVERT, (time_t)0); INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL); INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL); + INT_SET(ddq->d_rtbwarns, ARCH_CONVERT, 0UL); ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1); } diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index 365a054..68e9896 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c @@ -617,7 +617,8 @@ xfs_qm_scall_setqlim( if (!capable(CAP_SYS_ADMIN)) return XFS_ERROR(EPERM); - if ((newlim->d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK)) == 0) + if ((newlim->d_fieldmask & + (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK|FS_DQ_WARNS_MASK)) == 0) return (0); tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM); @@ -702,12 +703,23 @@ xfs_qm_scall_setqlim( qdprintk("ihard %Ld < isoft %Ld\n", hard, soft); } + /* + * Update warnings counter(s) if requested + */ + if (newlim->d_fieldmask & FS_DQ_BWARNS) + INT_SET(ddq->d_bwarns, ARCH_CONVERT, newlim->d_bwarns); + if (newlim->d_fieldmask & FS_DQ_IWARNS) + INT_SET(ddq->d_iwarns, ARCH_CONVERT, newlim->d_iwarns); + if (newlim->d_fieldmask & FS_DQ_RTBWARNS) + INT_SET(ddq->d_rtbwarns, ARCH_CONVERT, newlim->d_rtbwarns); + if (id == 0) { /* * Timelimits for the super user set the relative time * the other users can be over quota for this file system. * If it is zero a default is used. Ditto for the default - * soft and hard limit values (already done, above). + * soft and hard limit values (already done, above), and + * for warnings. */ if (newlim->d_fieldmask & FS_DQ_BTIMER) { mp->m_quotainfo->qi_btimelimit = newlim->d_btimer; @@ -721,7 +733,13 @@ xfs_qm_scall_setqlim( mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer; INT_SET(ddq->d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer); } - } else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ { + if (newlim->d_fieldmask & FS_DQ_BWARNS) + mp->m_quotainfo->qi_bwarnlimit = newlim->d_bwarns; + if (newlim->d_fieldmask & FS_DQ_IWARNS) + mp->m_quotainfo->qi_iwarnlimit = newlim->d_iwarns; + if (newlim->d_fieldmask & FS_DQ_RTBWARNS) + mp->m_quotainfo->qi_rtbwarnlimit = newlim->d_rtbwarns; + } else { /* * If the user is now over quota, start the timelimit. * The user will not be 'warned'. -- cgit v0.10.2 From ad89d0212e32c5cf27dfcbad67b91a32b9878529 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Tue, 21 Jun 2005 15:57:57 +1000 Subject: [XFS] Remove some debugging code from quota syscalls. SGI-PV: 932952 SGI-Modid: xfs-linux-melb:xfs-kern:22929a Signed-off-by: Nathan Scott diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index 32ec7f4..46ce1e3 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -911,7 +911,6 @@ xfs_qm_dqget( if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) || (! XFS_IS_PQUOTA_ON(mp) && type == XFS_DQ_PROJ) || (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) { -printk("XQM: ESRCH1\n"); return (ESRCH); } h = XFS_DQ_HASH(mp, id, type); @@ -989,7 +988,6 @@ printk("XQM: ESRCH1\n"); &dqp))) { if (ip) xfs_ilock(ip, XFS_ILOCK_EXCL); -if (error == ESRCH) printk("XQM: ESRCH2\n"); return (error); } @@ -1015,7 +1013,6 @@ if (error == ESRCH) printk("XQM: ESRCH2\n"); if (! XFS_IS_DQTYPE_ON(mp, type)) { /* inode stays locked on return */ xfs_qm_dqdestroy(dqp); -printk("XQM: ESRCH3\n"); return XFS_ERROR(ESRCH); } /* -- cgit v0.10.2 From 18b504e25fd617bee8830d2cdcaff7fb7b5931bb Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Tue, 21 Jun 2005 12:38:48 -0700 Subject: [NETLINK]: netlink_callback structure needs 5 args not 4 net/ipv4/tcp_diag.c uses up to ->args[4] Signed-off-by: David S. Miller diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 561d4dc..3029cad 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -147,7 +147,7 @@ struct netlink_callback int (*dump)(struct sk_buff * skb, struct netlink_callback *cb); int (*done)(struct netlink_callback *cb); int family; - long args[4]; + long args[5]; }; struct netlink_notify -- cgit v0.10.2 From 19baf839ff4a8daa1f2a7400897094fc18e4f5e9 Mon Sep 17 00:00:00 2001 From: Robert Olsson Date: Tue, 21 Jun 2005 12:43:18 -0700 Subject: [IPV4]: Add LC-Trie FIB lookup algorithm. Signed-off-by: Robert Olsson Signed-off-by: David S. Miller diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 6d3e8b1..05107e0 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -1,6 +1,32 @@ # # IP configuration # +choice + prompt "Choose IP: FIB lookup"" + depends on INET + default IP_FIB_HASH + +config IP_FIB_HASH + bool "FIB_HASH" + ---help--- + Current FIB is very proven and good enough for most users. + +config IP_FIB_TRIE + bool "FIB_TRIE" + ---help--- + Use new experimental LC-trie as FIB lookup algoritm. + This improves lookup performance + + LC-trie is described in: + + IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson + IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999 + An experimental study of compression methods for dynamic tries + Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002. + http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/ + +endchoice + config IP_MULTICAST bool "IP: multicasting" depends on INET diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 8b379627..65d57d8 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -7,8 +7,10 @@ obj-y := utils.o route.o inetpeer.o protocol.o \ ip_output.o ip_sockglue.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o tcp_minisocks.o \ datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ - sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o + sysctl_net_ipv4.o fib_frontend.o fib_semantics.o +obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o +obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o obj-$(CONFIG_IP_MROUTE) += ipmr.o diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 03942f1..658e797 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1119,6 +1119,10 @@ module_init(inet_init); #ifdef CONFIG_PROC_FS extern int fib_proc_init(void); extern void fib_proc_exit(void); +#ifdef CONFIG_IP_FIB_TRIE +extern int fib_stat_proc_init(void); +extern void fib_stat_proc_exit(void); +#endif extern int ip_misc_proc_init(void); extern int raw_proc_init(void); extern void raw_proc_exit(void); @@ -1139,11 +1143,19 @@ static int __init ipv4_proc_init(void) goto out_udp; if (fib_proc_init()) goto out_fib; +#ifdef CONFIG_IP_FIB_TRIE + if (fib_stat_proc_init()) + goto out_fib_stat; + #endif if (ip_misc_proc_init()) goto out_misc; out: return rc; out_misc: +#ifdef CONFIG_IP_FIB_TRIE + fib_stat_proc_exit(); +out_fib_stat: +#endif fib_proc_exit(); out_fib: udp4_proc_exit(); diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c new file mode 100644 index 0000000..c0ece94 --- /dev/null +++ b/net/ipv4/fib_trie.c @@ -0,0 +1,2454 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Robert Olsson Uppsala Universitet + * & Swedish University of Agricultural Sciences. + * + * Jens Laas Swedish University of + * Agricultural Sciences. + * + * Hans Liss Uppsala Universitet + * + * This work is based on the LPC-trie which is originally descibed in: + * + * An experimental study of compression methods for dynamic tries + * Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002. + * http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/ + * + * + * IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson + * IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999 + * + * Version: $Id: fib_trie.c,v 1.3 2005/06/08 14:20:01 robert Exp $ + * + * + * Code from fib_hash has been reused which includes the following header: + * + * + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IPv4 FIB: lookup engine and maintenance routines. + * + * + * Authors: Alexey Kuznetsov, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#define VERSION "0.323" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fib_lookup.h" + +#undef CONFIG_IP_FIB_TRIE_STATS +#define MAX_CHILDS 16384 + +#define EXTRACT(p, n, str) ((str)<<(p)>>(32-(n))) +#define KEYLENGTH (8*sizeof(t_key)) +#define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l)) +#define TKEY_GET_MASK(offset, bits) (((bits)==0)?0:((t_key)(-1) << (KEYLENGTH - bits) >> offset)) + +static DEFINE_RWLOCK(fib_lock); + +typedef unsigned int t_key; + +#define T_TNODE 0 +#define T_LEAF 1 +#define NODE_TYPE_MASK 0x1UL +#define NODE_PARENT(_node) \ +((struct tnode *)((_node)->_parent & ~NODE_TYPE_MASK)) +#define NODE_SET_PARENT(_node, _ptr) \ +((_node)->_parent = (((unsigned long)(_ptr)) | \ + ((_node)->_parent & NODE_TYPE_MASK))) +#define NODE_INIT_PARENT(_node, _type) \ +((_node)->_parent = (_type)) +#define NODE_TYPE(_node) \ +((_node)->_parent & NODE_TYPE_MASK) + +#define IS_TNODE(n) (!(n->_parent & T_LEAF)) +#define IS_LEAF(n) (n->_parent & T_LEAF) + +struct node { + t_key key; + unsigned long _parent; +}; + +struct leaf { + t_key key; + unsigned long _parent; + struct hlist_head list; +}; + +struct leaf_info { + struct hlist_node hlist; + int plen; + struct list_head falh; +}; + +struct tnode { + t_key key; + unsigned long _parent; + unsigned short pos:5; /* 2log(KEYLENGTH) bits needed */ + unsigned short bits:5; /* 2log(KEYLENGTH) bits needed */ + unsigned short full_children; /* KEYLENGTH bits needed */ + unsigned short empty_children; /* KEYLENGTH bits needed */ + struct node *child[0]; +}; + +#ifdef CONFIG_IP_FIB_TRIE_STATS +struct trie_use_stats { + unsigned int gets; + unsigned int backtrack; + unsigned int semantic_match_passed; + unsigned int semantic_match_miss; + unsigned int null_node_hit; +}; +#endif + +struct trie_stat { + unsigned int totdepth; + unsigned int maxdepth; + unsigned int tnodes; + unsigned int leaves; + unsigned int nullpointers; + unsigned int nodesizes[MAX_CHILDS]; +}; + +struct trie { + struct node *trie; +#ifdef CONFIG_IP_FIB_TRIE_STATS + struct trie_use_stats stats; +#endif + int size; + unsigned int revision; +}; + +static int trie_debug = 0; + +static int tnode_full(struct tnode *tn, struct node *n); +static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n); +static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull); +static int tnode_child_length(struct tnode *tn); +static struct node *resize(struct trie *t, struct tnode *tn); +static struct tnode *inflate(struct trie *t, struct tnode *tn); +static struct tnode *halve(struct trie *t, struct tnode *tn); +static void tnode_free(struct tnode *tn); +static void trie_dump_seq(struct seq_file *seq, struct trie *t); +extern struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio); +extern int fib_detect_death(struct fib_info *fi, int order, + struct fib_info **last_resort, int *last_idx, int *dflt); + +extern void rtmsg_fib(int event, u32 key, struct fib_alias *fa, int z, int tb_id, + struct nlmsghdr *n, struct netlink_skb_parms *req); + +static kmem_cache_t *fn_alias_kmem; +static struct trie *trie_local = NULL, *trie_main = NULL; + +static void trie_bug(char *err) +{ + printk("Trie Bug: %s\n", err); + BUG(); +} + +static inline struct node *tnode_get_child(struct tnode *tn, int i) +{ + if (i >= 1<bits) + trie_bug("tnode_get_child"); + + return tn->child[i]; +} + +static inline int tnode_child_length(struct tnode *tn) +{ + return 1<bits; +} + +/* + _________________________________________________________________ + | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C | + ---------------------------------------------------------------- + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + + _________________________________________________________________ + | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u | + ----------------------------------------------------------------- + 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + + tp->pos = 7 + tp->bits = 3 + n->pos = 15 + n->bits=4 + KEYLENGTH=32 +*/ + +static inline t_key tkey_extract_bits(t_key a, int offset, int bits) +{ + if (offset < KEYLENGTH) + return ((t_key)(a << offset)) >> (KEYLENGTH - bits); + else + return 0; +} + +static inline int tkey_equals(t_key a, t_key b) +{ + return a == b; +} + +static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b) +{ + if (bits == 0 || offset >= KEYLENGTH) + return 1; + bits = bits > KEYLENGTH ? KEYLENGTH : bits; + return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0; +} + +static inline int tkey_mismatch(t_key a, int offset, t_key b) +{ + t_key diff = a ^ b; + int i = offset; + + if(!diff) + return 0; + while((diff << i) >> (KEYLENGTH-1) == 0) + i++; + return i; +} + +/* Candiate for fib_semantics */ + +static void fn_free_alias(struct fib_alias *fa) +{ + fib_release_info(fa->fa_info); + kmem_cache_free(fn_alias_kmem, fa); +} + +/* + To understand this stuff, an understanding of keys and all their bits is + necessary. Every node in the trie has a key associated with it, but not + all of the bits in that key are significant. + + Consider a node 'n' and its parent 'tp'. + + If n is a leaf, every bit in its key is significant. Its presence is + necessitaded by path compression, since during a tree traversal (when + searching for a leaf - unless we are doing an insertion) we will completely + ignore all skipped bits we encounter. Thus we need to verify, at the end of + a potentially successful search, that we have indeed been walking the + correct key path. + + Note that we can never "miss" the correct key in the tree if present by + following the wrong path. Path compression ensures that segments of the key + that are the same for all keys with a given prefix are skipped, but the + skipped part *is* identical for each node in the subtrie below the skipped + bit! trie_insert() in this implementation takes care of that - note the + call to tkey_sub_equals() in trie_insert(). + + if n is an internal node - a 'tnode' here, the various parts of its key + have many different meanings. + + Example: + _________________________________________________________________ + | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C | + ----------------------------------------------------------------- + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + + _________________________________________________________________ + | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u | + ----------------------------------------------------------------- + 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + + tp->pos = 7 + tp->bits = 3 + n->pos = 15 + n->bits=4 + + First, let's just ignore the bits that come before the parent tp, that is + the bits from 0 to (tp->pos-1). They are *known* but at this point we do + not use them for anything. + + The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the + index into the parent's child array. That is, they will be used to find + 'n' among tp's children. + + The bits from (tp->pos + tp->bits) to (n->pos - 1) - "S" - are skipped bits + for the node n. + + All the bits we have seen so far are significant to the node n. The rest + of the bits are really not needed or indeed known in n->key. + + The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into + n's child array, and will of course be different for each child. + + The rest of the bits, from (n->pos + n->bits) onward, are completely unknown + at this point. + +*/ + +static void check_tnode(struct tnode *tn) +{ + if(tn && tn->pos+tn->bits > 32) { + printk("TNODE ERROR tn=%p, pos=%d, bits=%d\n", tn, tn->pos, tn->bits); + } +} + +static int halve_threshold = 25; +static int inflate_threshold = 50; + +static struct leaf *leaf_new(void) +{ + struct leaf *l = kmalloc(sizeof(struct leaf), GFP_KERNEL); + if(l) { + NODE_INIT_PARENT(l, T_LEAF); + INIT_HLIST_HEAD(&l->list); + } + return l; +} + +static struct leaf_info *leaf_info_new(int plen) +{ + struct leaf_info *li = kmalloc(sizeof(struct leaf_info), GFP_KERNEL); + li->plen = plen; + INIT_LIST_HEAD(&li->falh); + return li; +} + +static inline void free_leaf(struct leaf *l) +{ + kfree(l); +} + +static inline void free_leaf_info(struct leaf_info *li) +{ + kfree(li); +} + +static struct tnode* tnode_new(t_key key, int pos, int bits) +{ + int nchildren = 1<pos = pos; + tn->bits = bits; + tn->key = key; + tn->full_children = 0; + tn->empty_children = 1< 0) + printk("AT %p s=%u %u\n", tn, (unsigned int) sizeof(struct tnode), + (unsigned int) (sizeof(struct node) * 1< 0 ) + printk("FL %p \n", tn); + } + else if(IS_TNODE(tn)) { + kfree(tn); + if(trie_debug > 0 ) + printk("FT %p \n", tn); + } + else { + trie_bug("tnode_free\n"); + } +} + +/* + * Check whether a tnode 'n' is "full", i.e. it is an internal node + * and no bits are skipped. See discussion in dyntree paper p. 6 + */ + +static inline int tnode_full(struct tnode *tn, struct node *n) +{ + if(n == NULL || IS_LEAF(n)) + return 0; + + return ((struct tnode *) n)->pos == tn->pos + tn->bits; +} + +static inline void put_child(struct trie *t, struct tnode *tn, int i, struct node *n) +{ + tnode_put_child_reorg(tn, i, n, -1); +} + + /* + * Add a child at position i overwriting the old value. + * Update the value of full_children and empty_children. + */ + +static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull) +{ + struct node *chi; + int isfull; + + if(i >= 1<bits) { + printk("bits=%d, i=%d\n", tn->bits, i); + trie_bug("tnode_put_child_reorg bits"); + } + write_lock_bh(&fib_lock); + chi = tn->child[i]; + + /* update emptyChildren */ + if (n == NULL && chi != NULL) + tn->empty_children++; + else if (n != NULL && chi == NULL) + tn->empty_children--; + + /* update fullChildren */ + if (wasfull == -1) + wasfull = tnode_full(tn, chi); + + isfull = tnode_full(tn, n); + if (wasfull && !isfull) + tn->full_children--; + + else if (!wasfull && isfull) + tn->full_children++; + if(n) + NODE_SET_PARENT(n, tn); + + tn->child[i] = n; + write_unlock_bh(&fib_lock); +} + +static struct node *resize(struct trie *t, struct tnode *tn) +{ + int i; + + if (!tn) + return NULL; + + if(trie_debug) + printk("In tnode_resize %p inflate_threshold=%d threshold=%d\n", + tn, inflate_threshold, halve_threshold); + + /* No children */ + if (tn->empty_children == tnode_child_length(tn)) { + tnode_free(tn); + return NULL; + } + /* One child */ + if (tn->empty_children == tnode_child_length(tn) - 1) + for (i = 0; i < tnode_child_length(tn); i++) { + + write_lock_bh(&fib_lock); + if (tn->child[i] != NULL) { + + /* compress one level */ + struct node *n = tn->child[i]; + if(n) + NODE_INIT_PARENT(n, NODE_TYPE(n)); + + write_unlock_bh(&fib_lock); + tnode_free(tn); + return n; + } + write_unlock_bh(&fib_lock); + } + /* + * Double as long as the resulting node has a number of + * nonempty nodes that are above the threshold. + */ + + /* + * From "Implementing a dynamic compressed trie" by Stefan Nilsson of + * the Helsinki University of Technology and Matti Tikkanen of Nokia + * Telecommunications, page 6: + * "A node is doubled if the ratio of non-empty children to all + * children in the *doubled* node is at least 'high'." + * + * 'high' in this instance is the variable 'inflate_threshold'. It + * is expressed as a percentage, so we multiply it with + * tnode_child_length() and instead of multiplying by 2 (since the + * child array will be doubled by inflate()) and multiplying + * the left-hand side by 100 (to handle the percentage thing) we + * multiply the left-hand side by 50. + * + * The left-hand side may look a bit weird: tnode_child_length(tn) + * - tn->empty_children is of course the number of non-null children + * in the current node. tn->full_children is the number of "full" + * children, that is non-null tnodes with a skip value of 0. + * All of those will be doubled in the resulting inflated tnode, so + * we just count them one extra time here. + * + * A clearer way to write this would be: + * + * to_be_doubled = tn->full_children; + * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children - + * tn->full_children; + * + * new_child_length = tnode_child_length(tn) * 2; + * + * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) / + * new_child_length; + * if (new_fill_factor >= inflate_threshold) + * + * ...and so on, tho it would mess up the while() loop. + * + * anyway, + * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >= + * inflate_threshold + * + * avoid a division: + * 100 * (not_to_be_doubled + 2*to_be_doubled) >= + * inflate_threshold * new_child_length + * + * expand not_to_be_doubled and to_be_doubled, and shorten: + * 100 * (tnode_child_length(tn) - tn->empty_children + + * tn->full_children ) >= inflate_threshold * new_child_length + * + * expand new_child_length: + * 100 * (tnode_child_length(tn) - tn->empty_children + + * tn->full_children ) >= + * inflate_threshold * tnode_child_length(tn) * 2 + * + * shorten again: + * 50 * (tn->full_children + tnode_child_length(tn) - + * tn->empty_children ) >= inflate_threshold * + * tnode_child_length(tn) + * + */ + + check_tnode(tn); + + while ((tn->full_children > 0 && + 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >= + inflate_threshold * tnode_child_length(tn))) { + + tn = inflate(t, tn); + } + + check_tnode(tn); + + /* + * Halve as long as the number of empty children in this + * node is above threshold. + */ + while (tn->bits > 1 && + 100 * (tnode_child_length(tn) - tn->empty_children) < + halve_threshold * tnode_child_length(tn)) + + tn = halve(t, tn); + + /* Only one child remains */ + + if (tn->empty_children == tnode_child_length(tn) - 1) + for (i = 0; i < tnode_child_length(tn); i++) { + + write_lock_bh(&fib_lock); + if (tn->child[i] != NULL) { + /* compress one level */ + struct node *n = tn->child[i]; + + if(n) + NODE_INIT_PARENT(n, NODE_TYPE(n)); + + write_unlock_bh(&fib_lock); + tnode_free(tn); + return n; + } + write_unlock_bh(&fib_lock); + } + + return (struct node *) tn; +} + +static struct tnode *inflate(struct trie *t, struct tnode *tn) +{ + struct tnode *inode; + struct tnode *oldtnode = tn; + int olen = tnode_child_length(tn); + int i; + + if(trie_debug) + printk("In inflate\n"); + + tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1); + + if (!tn) + trie_bug("tnode_new failed"); + + for(i = 0; i < olen; i++) { + struct node *node = tnode_get_child(oldtnode, i); + + /* An empty child */ + if (node == NULL) + continue; + + /* A leaf or an internal node with skipped bits */ + + if(IS_LEAF(node) || ((struct tnode *) node)->pos > + tn->pos + tn->bits - 1) { + if(tkey_extract_bits(node->key, tn->pos + tn->bits - 1, + 1) == 0) + put_child(t, tn, 2*i, node); + else + put_child(t, tn, 2*i+1, node); + continue; + } + + /* An internal node with two children */ + inode = (struct tnode *) node; + + if (inode->bits == 1) { + put_child(t, tn, 2*i, inode->child[0]); + put_child(t, tn, 2*i+1, inode->child[1]); + + tnode_free(inode); + } + + /* An internal node with more than two children */ + else { + struct tnode *left, *right; + int size, j; + + /* We will replace this node 'inode' with two new + * ones, 'left' and 'right', each with half of the + * original children. The two new nodes will have + * a position one bit further down the key and this + * means that the "significant" part of their keys + * (see the discussion near the top of this file) + * will differ by one bit, which will be "0" in + * left's key and "1" in right's key. Since we are + * moving the key position by one step, the bit that + * we are moving away from - the bit at position + * (inode->pos) - is the one that will differ between + * left and right. So... we synthesize that bit in the + * two new keys. + * The mask 'm' below will be a single "one" bit at + * the position (inode->pos) + */ + + t_key m = TKEY_GET_MASK(inode->pos, 1); + + /* Use the old key, but set the new significant + * bit to zero. + */ + left = tnode_new(inode->key&(~m), inode->pos + 1, + inode->bits - 1); + + if(!left) + trie_bug("tnode_new failed"); + + + /* Use the old key, but set the new significant + * bit to one. + */ + right = tnode_new(inode->key|m, inode->pos + 1, + inode->bits - 1); + + if(!right) + trie_bug("tnode_new failed"); + + size = tnode_child_length(left); + for(j = 0; j < size; j++) { + put_child(t, left, j, inode->child[j]); + put_child(t, right, j, inode->child[j + size]); + } + put_child(t, tn, 2*i, resize(t, left)); + put_child(t, tn, 2*i+1, resize(t, right)); + + tnode_free(inode); + } + } + tnode_free(oldtnode); + return tn; +} + +static struct tnode *halve(struct trie *t, struct tnode *tn) +{ + struct tnode *oldtnode = tn; + struct node *left, *right; + int i; + int olen = tnode_child_length(tn); + + if(trie_debug) printk("In halve\n"); + + tn=tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1); + + if(!tn) + trie_bug("tnode_new failed"); + + for(i = 0; i < olen; i += 2) { + left = tnode_get_child(oldtnode, i); + right = tnode_get_child(oldtnode, i+1); + + /* At least one of the children is empty */ + if (left == NULL) { + if (right == NULL) /* Both are empty */ + continue; + put_child(t, tn, i/2, right); + } else if (right == NULL) + put_child(t, tn, i/2, left); + + /* Two nonempty children */ + else { + struct tnode *newBinNode = + tnode_new(left->key, tn->pos + tn->bits, 1); + + if(!newBinNode) + trie_bug("tnode_new failed"); + + put_child(t, newBinNode, 0, left); + put_child(t, newBinNode, 1, right); + put_child(t, tn, i/2, resize(t, newBinNode)); + } + } + tnode_free(oldtnode); + return tn; +} + +static void *trie_init(struct trie *t) +{ + if(t) { + t->size = 0; + t->trie = NULL; + t->revision = 0; +#ifdef CONFIG_IP_FIB_TRIE_STATS + memset(&t->stats, 0, sizeof(struct trie_use_stats)); +#endif + } + return t; +} + +static struct leaf_info *find_leaf_info(struct hlist_head *head, int plen) +{ + struct hlist_node *node; + struct leaf_info *li; + + hlist_for_each_entry(li, node, head, hlist) { + + if ( li->plen == plen ) + return li; + } + return NULL; +} + +static inline struct list_head * get_fa_head(struct leaf *l, int plen) +{ + struct list_head *fa_head=NULL; + struct leaf_info *li = find_leaf_info(&l->list, plen); + + if(li) + fa_head = &li->falh; + + return fa_head; +} + +static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new) +{ + struct leaf_info *li=NULL, *last=NULL; + struct hlist_node *node, *tmp; + + write_lock_bh(&fib_lock); + + if(hlist_empty(head)) + hlist_add_head(&new->hlist, head); + else { + hlist_for_each_entry_safe(li, node, tmp, head, hlist) { + + if (new->plen > li->plen) + break; + + last = li; + } + if(last) + hlist_add_after(&last->hlist, &new->hlist); + else + hlist_add_before(&new->hlist, &li->hlist); + } + write_unlock_bh(&fib_lock); +} + +static struct leaf * +fib_find_node(struct trie *t, u32 key) +{ + int pos; + struct tnode *tn; + struct node *n; + + pos = 0; + n=t->trie; + + while (n != NULL && NODE_TYPE(n) == T_TNODE) { + tn = (struct tnode *) n; + + check_tnode(tn); + + if(tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { + pos=tn->pos + tn->bits; + n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits)); + } + else + break; + } + /* Case we have found a leaf. Compare prefixes */ + + if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) { + struct leaf *l = (struct leaf *) n; + return l; + } + return NULL; +} + +static struct node *trie_rebalance(struct trie *t, struct tnode *tn) +{ + int i = 0; + int wasfull; + t_key cindex, key; + struct tnode *tp = NULL; + + if(!tn) + BUG(); + + key = tn->key; + i = 0; + + while (tn != NULL && NODE_PARENT(tn) != NULL) { + + if( i > 10 ) { + printk("Rebalance tn=%p \n", tn); + if(tn) printk("tn->parent=%p \n", NODE_PARENT(tn)); + + printk("Rebalance tp=%p \n", tp); + if(tp) printk("tp->parent=%p \n", NODE_PARENT(tp)); + } + + if( i > 12 ) BUG(); + i++; + + tp = NODE_PARENT(tn); + cindex = tkey_extract_bits(key, tp->pos, tp->bits); + wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); + tn = (struct tnode *) resize (t, (struct tnode *)tn); + tnode_put_child_reorg((struct tnode *)tp, cindex,(struct node*)tn, wasfull); + + if(!NODE_PARENT(tn)) + break; + + tn = NODE_PARENT(tn); + } + /* Handle last (top) tnode */ + if (IS_TNODE(tn)) + tn = (struct tnode*) resize(t, (struct tnode *)tn); + + return (struct node*) tn; +} + +static struct list_head * +fib_insert_node(struct trie *t, u32 key, int plen) +{ + int pos, newpos; + struct tnode *tp = NULL, *tn = NULL; + struct node *n; + struct leaf *l; + int missbit; + struct list_head *fa_head=NULL; + struct leaf_info *li; + t_key cindex; + + pos = 0; + n=t->trie; + + /* If we point to NULL, stop. Either the tree is empty and we should + * just put a new leaf in if, or we have reached an empty child slot, + * and we should just put our new leaf in that. + * If we point to a T_TNODE, check if it matches our key. Note that + * a T_TNODE might be skipping any number of bits - its 'pos' need + * not be the parent's 'pos'+'bits'! + * + * If it does match the current key, get pos/bits from it, extract + * the index from our key, push the T_TNODE and walk the tree. + * + * If it doesn't, we have to replace it with a new T_TNODE. + * + * If we point to a T_LEAF, it might or might not have the same key + * as we do. If it does, just change the value, update the T_LEAF's + * value, and return it. + * If it doesn't, we need to replace it with a T_TNODE. + */ + + while (n != NULL && NODE_TYPE(n) == T_TNODE) { + tn = (struct tnode *) n; + + check_tnode(tn); + + if(tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { + tp = tn; + pos=tn->pos + tn->bits; + n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits)); + + if(n && NODE_PARENT(n) != tn) { + printk("BUG tn=%p, n->parent=%p\n", tn, NODE_PARENT(n)); + BUG(); + } + } + else + break; + } + + /* + * n ----> NULL, LEAF or TNODE + * + * tp is n's (parent) ----> NULL or TNODE + */ + + if(tp && IS_LEAF(tp)) + BUG(); + + t->revision++; + + /* Case 1: n is a leaf. Compare prefixes */ + + if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) { + struct leaf *l = ( struct leaf *) n; + + li = leaf_info_new(plen); + + if(! li) + BUG(); + + fa_head = &li->falh; + insert_leaf_info(&l->list, li); + goto done; + } + t->size++; + l = leaf_new(); + + if(! l) + BUG(); + + l->key = key; + li = leaf_info_new(plen); + + if(! li) + BUG(); + + fa_head = &li->falh; + insert_leaf_info(&l->list, li); + + /* Case 2: n is NULL, and will just insert a new leaf */ + if (t->trie && n == NULL) { + + NODE_SET_PARENT(l, tp); + + if (!tp) + BUG(); + + else { + cindex = tkey_extract_bits(key, tp->pos, tp->bits); + put_child(t, (struct tnode *)tp, cindex, (struct node *)l); + } + } + /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */ + else { + /* + * Add a new tnode here + * first tnode need some special handling + */ + + if (tp) + pos=tp->pos+tp->bits; + else + pos=0; + if(n) { + newpos = tkey_mismatch(key, pos, n->key); + tn = tnode_new(n->key, newpos, 1); + } + else { + newpos = 0; + tn = tnode_new(key, newpos, 1); /* First tnode */ + } + if(!tn) + trie_bug("tnode_pfx_new failed"); + + NODE_SET_PARENT(tn, tp); + + missbit=tkey_extract_bits(key, newpos, 1); + put_child(t, tn, missbit, (struct node *)l); + put_child(t, tn, 1-missbit, n); + + if(tp) { + cindex = tkey_extract_bits(key, tp->pos, tp->bits); + put_child(t, (struct tnode *)tp, cindex, (struct node *)tn); + } + else { + t->trie = (struct node*) tn; /* First tnode */ + tp = tn; + } + } + if(tp && tp->pos+tp->bits > 32) { + printk("ERROR tp=%p pos=%d, bits=%d, key=%0x plen=%d\n", + tp, tp->pos, tp->bits, key, plen); + } + /* Rebalance the trie */ + t->trie = trie_rebalance(t, tp); +done:; + return fa_head; +} + +static int +fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, + struct nlmsghdr *nlhdr, struct netlink_skb_parms *req) +{ + struct trie *t = (struct trie *) tb->tb_data; + struct fib_alias *fa, *new_fa; + struct list_head *fa_head=NULL; + struct fib_info *fi; + int plen = r->rtm_dst_len; + int type = r->rtm_type; + u8 tos = r->rtm_tos; + u32 key, mask; + int err; + struct leaf *l; + + if (plen > 32) + return -EINVAL; + + key = 0; + if (rta->rta_dst) + memcpy(&key, rta->rta_dst, 4); + + key = ntohl(key); + + if(trie_debug) + printk("Insert table=%d %08x/%d\n", tb->tb_id, key, plen); + + mask = ntohl( inet_make_mask(plen) ); + + if(key & ~mask) + return -EINVAL; + + key = key & mask; + + if ((fi = fib_create_info(r, rta, nlhdr, &err)) == NULL) + goto err; + + l = fib_find_node(t, key); + fa = NULL; + + if(l) { + fa_head = get_fa_head(l, plen); + fa = fib_find_alias(fa_head, tos, fi->fib_priority); + } + + /* Now fa, if non-NULL, points to the first fib alias + * with the same keys [prefix,tos,priority], if such key already + * exists or to the node before which we will insert new one. + * + * If fa is NULL, we will need to allocate a new one and + * insert to the head of f. + * + * If f is NULL, no fib node matched the destination key + * and we need to allocate a new one of those as well. + */ + + if (fa && + fa->fa_info->fib_priority == fi->fib_priority) { + struct fib_alias *fa_orig; + + err = -EEXIST; + if (nlhdr->nlmsg_flags & NLM_F_EXCL) + goto out; + + if (nlhdr->nlmsg_flags & NLM_F_REPLACE) { + struct fib_info *fi_drop; + u8 state; + + write_lock_bh(&fib_lock); + + fi_drop = fa->fa_info; + fa->fa_info = fi; + fa->fa_type = type; + fa->fa_scope = r->rtm_scope; + state = fa->fa_state; + fa->fa_state &= ~FA_S_ACCESSED; + + write_unlock_bh(&fib_lock); + + fib_release_info(fi_drop); + if (state & FA_S_ACCESSED) + rt_cache_flush(-1); + + goto succeeded; + } + /* Error if we find a perfect match which + * uses the same scope, type, and nexthop + * information. + */ + fa_orig = fa; + list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) { + if (fa->fa_tos != tos) + break; + if (fa->fa_info->fib_priority != fi->fib_priority) + break; + if (fa->fa_type == type && + fa->fa_scope == r->rtm_scope && + fa->fa_info == fi) { + goto out; + } + } + if (!(nlhdr->nlmsg_flags & NLM_F_APPEND)) + fa = fa_orig; + } + err = -ENOENT; + if (!(nlhdr->nlmsg_flags&NLM_F_CREATE)) + goto out; + + err = -ENOBUFS; + new_fa = kmem_cache_alloc(fn_alias_kmem, SLAB_KERNEL); + if (new_fa == NULL) + goto out; + + new_fa->fa_info = fi; + new_fa->fa_tos = tos; + new_fa->fa_type = type; + new_fa->fa_scope = r->rtm_scope; + new_fa->fa_state = 0; +#if 0 + new_fa->dst = NULL; +#endif + /* + * Insert new entry to the list. + */ + + if(!fa_head) + fa_head = fib_insert_node(t, key, plen); + + write_lock_bh(&fib_lock); + + list_add_tail(&new_fa->fa_list, + (fa ? &fa->fa_list : fa_head)); + + write_unlock_bh(&fib_lock); + + rt_cache_flush(-1); + rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req); +succeeded: + return 0; +out: + fib_release_info(fi); +err:; + return err; +} + +static inline int check_leaf(struct trie *t, struct leaf *l, t_key key, int *plen, const struct flowi *flp, + struct fib_result *res, int *err) +{ + int i; + t_key mask; + struct leaf_info *li; + struct hlist_head *hhead = &l->list; + struct hlist_node *node; + + hlist_for_each_entry(li, node, hhead, hlist) { + + i = li->plen; + mask = ntohl(inet_make_mask(i)); + if (l->key != (key & mask)) + continue; + + if (((*err) = fib_semantic_match(&li->falh, flp, res, l->key, mask, i)) == 0) { + *plen = i; +#ifdef CONFIG_IP_FIB_TRIE_STATS + t->stats.semantic_match_passed++; +#endif + return 1; + } +#ifdef CONFIG_IP_FIB_TRIE_STATS + t->stats.semantic_match_miss++; +#endif + } + return 0; +} + +static int +fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res) +{ + struct trie *t = (struct trie *) tb->tb_data; + int plen, ret = 0; + struct node *n; + struct tnode *pn; + int pos, bits; + t_key key=ntohl(flp->fl4_dst); + int chopped_off; + t_key cindex = 0; + int current_prefix_length = KEYLENGTH; + n = t->trie; + + read_lock(&fib_lock); + if(!n) + goto failed; + +#ifdef CONFIG_IP_FIB_TRIE_STATS + t->stats.gets++; +#endif + + /* Just a leaf? */ + if (IS_LEAF(n)) { + if( check_leaf(t, (struct leaf *)n, key, &plen, flp, res, &ret) ) + goto found; + goto failed; + } + pn = (struct tnode *) n; + chopped_off = 0; + + while (pn) { + + pos = pn->pos; + bits = pn->bits; + + if(!chopped_off) + cindex = tkey_extract_bits(MASK_PFX(key, current_prefix_length), pos, bits); + + n = tnode_get_child(pn, cindex); + + if (n == NULL) { +#ifdef CONFIG_IP_FIB_TRIE_STATS + t->stats.null_node_hit++; +#endif + goto backtrace; + } + + if (IS_TNODE(n)) { +#define HL_OPTIMIZE +#ifdef HL_OPTIMIZE + struct tnode *cn = (struct tnode *)n; + t_key node_prefix, key_prefix, pref_mismatch; + int mp; + + /* + * It's a tnode, and we can do some extra checks here if we + * like, to avoid descending into a dead-end branch. + * This tnode is in the parent's child array at index + * key[p_pos..p_pos+p_bits] but potentially with some bits + * chopped off, so in reality the index may be just a + * subprefix, padded with zero at the end. + * We can also take a look at any skipped bits in this + * tnode - everything up to p_pos is supposed to be ok, + * and the non-chopped bits of the index (se previous + * paragraph) are also guaranteed ok, but the rest is + * considered unknown. + * + * The skipped bits are key[pos+bits..cn->pos]. + */ + + /* If current_prefix_length < pos+bits, we are already doing + * actual prefix matching, which means everything from + * pos+(bits-chopped_off) onward must be zero along some + * branch of this subtree - otherwise there is *no* valid + * prefix present. Here we can only check the skipped + * bits. Remember, since we have already indexed into the + * parent's child array, we know that the bits we chopped of + * *are* zero. + */ + + /* NOTA BENE: CHECKING ONLY SKIPPED BITS FOR THE NEW NODE HERE */ + + if (current_prefix_length < pos+bits) { + if (tkey_extract_bits(cn->key, current_prefix_length, + cn->pos - current_prefix_length) != 0 || + !(cn->child[0])) + goto backtrace; + } + + /* + * If chopped_off=0, the index is fully validated and we + * only need to look at the skipped bits for this, the new, + * tnode. What we actually want to do is to find out if + * these skipped bits match our key perfectly, or if we will + * have to count on finding a matching prefix further down, + * because if we do, we would like to have some way of + * verifying the existence of such a prefix at this point. + */ + + /* The only thing we can do at this point is to verify that + * any such matching prefix can indeed be a prefix to our + * key, and if the bits in the node we are inspecting that + * do not match our key are not ZERO, this cannot be true. + * Thus, find out where there is a mismatch (before cn->pos) + * and verify that all the mismatching bits are zero in the + * new tnode's key. + */ + + /* Note: We aren't very concerned about the piece of the key + * that precede pn->pos+pn->bits, since these have already been + * checked. The bits after cn->pos aren't checked since these are + * by definition "unknown" at this point. Thus, what we want to + * see is if we are about to enter the "prefix matching" state, + * and in that case verify that the skipped bits that will prevail + * throughout this subtree are zero, as they have to be if we are + * to find a matching prefix. + */ + + node_prefix = MASK_PFX(cn->key, cn->pos); + key_prefix = MASK_PFX(key, cn->pos); + pref_mismatch = key_prefix^node_prefix; + mp = 0; + + /* In short: If skipped bits in this node do not match the search + * key, enter the "prefix matching" state.directly. + */ + if (pref_mismatch) { + while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) { + mp++; + pref_mismatch = pref_mismatch <<1; + } + key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp); + + if (key_prefix != 0) + goto backtrace; + + if (current_prefix_length >= cn->pos) + current_prefix_length=mp; + } +#endif + pn = (struct tnode *)n; /* Descend */ + chopped_off = 0; + continue; + } + if (IS_LEAF(n)) { + if( check_leaf(t, (struct leaf *)n, key, &plen, flp, res, &ret)) + goto found; + } +backtrace: + chopped_off++; + + /* As zero don't change the child key (cindex) */ + while ((chopped_off <= pn->bits) && !(cindex & (1<<(chopped_off-1)))) { + chopped_off++; + } + + /* Decrease current_... with bits chopped off */ + if (current_prefix_length > pn->pos + pn->bits - chopped_off) + current_prefix_length = pn->pos + pn->bits - chopped_off; + + /* + * Either we do the actual chop off according or if we have + * chopped off all bits in this tnode walk up to our parent. + */ + + if(chopped_off <= pn->bits) + cindex &= ~(1 << (chopped_off-1)); + else { + if( NODE_PARENT(pn) == NULL) + goto failed; + + /* Get Child's index */ + cindex = tkey_extract_bits(pn->key, NODE_PARENT(pn)->pos, NODE_PARENT(pn)->bits); + pn = NODE_PARENT(pn); + chopped_off = 0; + +#ifdef CONFIG_IP_FIB_TRIE_STATS + t->stats.backtrack++; +#endif + goto backtrace; + } + } +failed: + ret = 1; +found: + read_unlock(&fib_lock); + return ret; +} + +static int trie_leaf_remove(struct trie *t, t_key key) +{ + t_key cindex; + struct tnode *tp = NULL; + struct node *n = t->trie; + struct leaf *l; + + if(trie_debug) + printk("entering trie_leaf_remove(%p)\n", n); + + /* Note that in the case skipped bits, those bits are *not* checked! + * When we finish this, we will have NULL or a T_LEAF, and the + * T_LEAF may or may not match our key. + */ + + while (n != NULL && IS_TNODE(n)) { + struct tnode *tn = (struct tnode *) n; + check_tnode(tn); + n = tnode_get_child(tn ,tkey_extract_bits(key, tn->pos, tn->bits)); + + if(n && NODE_PARENT(n) != tn) { + printk("BUG tn=%p, n->parent=%p\n", tn, NODE_PARENT(n)); + BUG(); + } + } + l = (struct leaf *) n; + + if(!n || !tkey_equals(l->key, key)) + return 0; + + /* + * Key found. + * Remove the leaf and rebalance the tree + */ + + t->revision++; + t->size--; + + tp = NODE_PARENT(n); + tnode_free((struct tnode *) n); + + if(tp) { + cindex = tkey_extract_bits(key, tp->pos, tp->bits); + put_child(t, (struct tnode *)tp, cindex, NULL); + t->trie = trie_rebalance(t, tp); + } + else + t->trie = NULL; + + return 1; +} + +static int +fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, + struct nlmsghdr *nlhdr, struct netlink_skb_parms *req) +{ + struct trie *t = (struct trie *) tb->tb_data; + u32 key, mask; + int plen = r->rtm_dst_len; + u8 tos = r->rtm_tos; + struct fib_alias *fa, *fa_to_delete; + struct list_head *fa_head; + struct leaf *l; + + if (plen > 32) + return -EINVAL; + + key = 0; + if (rta->rta_dst) + memcpy(&key, rta->rta_dst, 4); + + key = ntohl(key); + mask = ntohl( inet_make_mask(plen) ); + + if(key & ~mask) + return -EINVAL; + + key = key & mask; + l = fib_find_node(t, key); + + if(!l) + return -ESRCH; + + fa_head = get_fa_head(l, plen); + fa = fib_find_alias(fa_head, tos, 0); + + if (!fa) + return -ESRCH; + + if (trie_debug) + printk("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t); + + fa_to_delete = NULL; + fa_head = fa->fa_list.prev; + list_for_each_entry(fa, fa_head, fa_list) { + struct fib_info *fi = fa->fa_info; + + if (fa->fa_tos != tos) + break; + + if ((!r->rtm_type || + fa->fa_type == r->rtm_type) && + (r->rtm_scope == RT_SCOPE_NOWHERE || + fa->fa_scope == r->rtm_scope) && + (!r->rtm_protocol || + fi->fib_protocol == r->rtm_protocol) && + fib_nh_match(r, nlhdr, rta, fi) == 0) { + fa_to_delete = fa; + break; + } + } + + if (fa_to_delete) { + int kill_li = 0; + struct leaf_info *li; + + fa = fa_to_delete; + rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req); + + l = fib_find_node(t, key); + li = find_leaf_info(&l->list, plen); + + write_lock_bh(&fib_lock); + + list_del(&fa->fa_list); + + if(list_empty(fa_head)) { + hlist_del(&li->hlist); + kill_li = 1; + } + write_unlock_bh(&fib_lock); + + if(kill_li) + free_leaf_info(li); + + if(hlist_empty(&l->list)) + trie_leaf_remove(t, key); + + if (fa->fa_state & FA_S_ACCESSED) + rt_cache_flush(-1); + + fn_free_alias(fa); + return 0; + } + return -ESRCH; +} + +static int trie_flush_list(struct trie *t, struct list_head *head) +{ + struct fib_alias *fa, *fa_node; + int found = 0; + + list_for_each_entry_safe(fa, fa_node, head, fa_list) { + struct fib_info *fi = fa->fa_info; + + if (fi && (fi->fib_flags&RTNH_F_DEAD)) { + + write_lock_bh(&fib_lock); + list_del(&fa->fa_list); + write_unlock_bh(&fib_lock); + + fn_free_alias(fa); + found++; + } + } + return found; +} + +static int trie_flush_leaf(struct trie *t, struct leaf *l) +{ + int found = 0; + struct hlist_head *lih = &l->list; + struct hlist_node *node, *tmp; + struct leaf_info *li = NULL; + + hlist_for_each_entry_safe(li, node, tmp, lih, hlist) { + + found += trie_flush_list(t, &li->falh); + + if (list_empty(&li->falh)) { + + write_lock_bh(&fib_lock); + hlist_del(&li->hlist); + write_unlock_bh(&fib_lock); + + free_leaf_info(li); + } + } + return found; +} + +static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf) +{ + struct node *c = (struct node *) thisleaf; + struct tnode *p; + int idx; + + if(c == NULL) { + if(t->trie == NULL) + return NULL; + + if (IS_LEAF(t->trie)) /* trie w. just a leaf */ + return (struct leaf *) t->trie; + + p = (struct tnode*) t->trie; /* Start */ + } + else + p = (struct tnode *) NODE_PARENT(c); + while (p) { + int pos, last; + + /* Find the next child of the parent */ + if(c) + pos = 1 + tkey_extract_bits(c->key, p->pos, p->bits); + else + pos = 0; + + last = 1 << p->bits; + for(idx = pos; idx < last ; idx++) { + if( p->child[idx]) { + + /* Decend if tnode */ + + while (IS_TNODE(p->child[idx])) { + p = (struct tnode*) p->child[idx]; + idx = 0; + + /* Rightmost non-NULL branch */ + if( p && IS_TNODE(p) ) + while ( p->child[idx] == NULL && idx < (1 << p->bits) ) idx++; + + /* Done with this tnode? */ + if( idx >= (1 << p->bits) || p->child[idx] == NULL ) + goto up; + } + return (struct leaf*) p->child[idx]; + } + } +up: + /* No more children go up one step */ + c = (struct node*) p; + p = (struct tnode *) NODE_PARENT(p); + } + return NULL; /* Ready. Root of trie */ +} + +static int fn_trie_flush(struct fib_table *tb) +{ + struct trie *t = (struct trie *) tb->tb_data; + struct leaf *ll = NULL, *l = NULL; + int found = 0, h; + + t->revision++; + + for (h=0; (l = nextleaf(t, l)) != NULL; h++) { + found += trie_flush_leaf(t, l); + + if (ll && hlist_empty(&ll->list)) + trie_leaf_remove(t, ll->key); + ll = l; + } + + if (ll && hlist_empty(&ll->list)) + trie_leaf_remove(t, ll->key); + + if(trie_debug) + printk("trie_flush found=%d\n", found); + return found; +} + +static int trie_last_dflt=-1; + +static void +fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res) +{ + struct trie *t = (struct trie *) tb->tb_data; + int order, last_idx; + struct fib_info *fi = NULL; + struct fib_info *last_resort; + struct fib_alias *fa = NULL; + struct list_head *fa_head; + struct leaf *l; + + last_idx = -1; + last_resort = NULL; + order = -1; + + read_lock(&fib_lock); + + l = fib_find_node(t, 0); + if(!l) + goto out; + + fa_head = get_fa_head(l, 0); + if(!fa_head) + goto out; + + if (list_empty(fa_head)) + goto out; + + list_for_each_entry(fa, fa_head, fa_list) { + struct fib_info *next_fi = fa->fa_info; + + if (fa->fa_scope != res->scope || + fa->fa_type != RTN_UNICAST) + continue; + + if (next_fi->fib_priority > res->fi->fib_priority) + break; + if (!next_fi->fib_nh[0].nh_gw || + next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) + continue; + fa->fa_state |= FA_S_ACCESSED; + + if (fi == NULL) { + if (next_fi != res->fi) + break; + } else if (!fib_detect_death(fi, order, &last_resort, + &last_idx, &trie_last_dflt)) { + if (res->fi) + fib_info_put(res->fi); + res->fi = fi; + atomic_inc(&fi->fib_clntref); + trie_last_dflt = order; + goto out; + } + fi = next_fi; + order++; + } + if (order <= 0 || fi == NULL) { + trie_last_dflt = -1; + goto out; + } + + if (!fib_detect_death(fi, order, &last_resort, &last_idx, &trie_last_dflt)) { + if (res->fi) + fib_info_put(res->fi); + res->fi = fi; + atomic_inc(&fi->fib_clntref); + trie_last_dflt = order; + goto out; + } + if (last_idx >= 0) { + if (res->fi) + fib_info_put(res->fi); + res->fi = last_resort; + if (last_resort) + atomic_inc(&last_resort->fib_clntref); + } + trie_last_dflt = last_idx; + out:; + read_unlock(&fib_lock); +} + +static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fib_table *tb, + struct sk_buff *skb, struct netlink_callback *cb) +{ + int i, s_i; + struct fib_alias *fa; + + u32 xkey=htonl(key); + + s_i=cb->args[3]; + i = 0; + + list_for_each_entry(fa, fah, fa_list) { + if (i < s_i) { + i++; + continue; + } + if (fa->fa_info->fib_nh == NULL) { + printk("Trie error _fib_nh=NULL in fa[%d] k=%08x plen=%d\n", i, key, plen); + i++; + continue; + } + if (fa->fa_info == NULL) { + printk("Trie error fa_info=NULL in fa[%d] k=%08x plen=%d\n", i, key, plen); + i++; + continue; + } + + if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + RTM_NEWROUTE, + tb->tb_id, + fa->fa_type, + fa->fa_scope, + &xkey, + plen, + fa->fa_tos, + fa->fa_info) < 0) { + cb->args[3] = i; + return -1; + } + i++; + } + cb->args[3]=i; + return skb->len; +} + +static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, struct sk_buff *skb, + struct netlink_callback *cb) +{ + int h, s_h; + struct list_head *fa_head; + struct leaf *l = NULL; + s_h=cb->args[2]; + + for (h=0; (l = nextleaf(t, l)) != NULL; h++) { + + if (h < s_h) + continue; + if (h > s_h) + memset(&cb->args[3], 0, + sizeof(cb->args) - 3*sizeof(cb->args[0])); + + fa_head = get_fa_head(l, plen); + + if(!fa_head) + continue; + + if(list_empty(fa_head)) + continue; + + if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) { + cb->args[2]=h; + return -1; + } + } + cb->args[2]=h; + return skb->len; +} + +static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb) +{ + int m, s_m; + struct trie *t = (struct trie *) tb->tb_data; + + s_m = cb->args[1]; + + read_lock(&fib_lock); + for (m=0; m<=32; m++) { + + if (m < s_m) + continue; + if (m > s_m) + memset(&cb->args[2], 0, + sizeof(cb->args) - 2*sizeof(cb->args[0])); + + if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) { + cb->args[1] = m; + goto out; + } + } + read_unlock(&fib_lock); + cb->args[1] = m; + return skb->len; + out: + read_unlock(&fib_lock); + return -1; +} + +/* Fix more generic FIB names for init later */ + +#ifdef CONFIG_IP_MULTIPLE_TABLES +struct fib_table * fib_hash_init(int id) +#else +struct fib_table * __init fib_hash_init(int id) +#endif +{ + struct fib_table *tb; + struct trie *t; + + if (fn_alias_kmem == NULL) + fn_alias_kmem = kmem_cache_create("ip_fib_alias", + sizeof(struct fib_alias), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + + tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie), + GFP_KERNEL); + if (tb == NULL) + return NULL; + + tb->tb_id = id; + tb->tb_lookup = fn_trie_lookup; + tb->tb_insert = fn_trie_insert; + tb->tb_delete = fn_trie_delete; + tb->tb_flush = fn_trie_flush; + tb->tb_select_default = fn_trie_select_default; + tb->tb_dump = fn_trie_dump; + memset(tb->tb_data, 0, sizeof(struct trie)); + + t = (struct trie *) tb->tb_data; + + trie_init(t); + + if (id == RT_TABLE_LOCAL) + trie_local=t; + else if (id == RT_TABLE_MAIN) + trie_main=t; + + if (id == RT_TABLE_LOCAL) + printk("IPv4 FIB: Using LC-trie version %s\n", VERSION); + + return tb; +} + +/* Trie dump functions */ + +static void putspace_seq(struct seq_file *seq, int n) +{ + while (n--) seq_printf(seq, " "); +} + +static void printbin_seq(struct seq_file *seq, unsigned int v, int bits) +{ + while (bits--) + seq_printf(seq, "%s", (v & (1<: "); + seq_printf(seq, "%s:%p ", IS_LEAF(n)?"Leaf":"Internal node", n); + + if (IS_LEAF(n)) + seq_printf(seq, "key=%d.%d.%d.%d\n", + n->key >> 24, (n->key >> 16) % 256, (n->key >> 8) % 256, n->key % 256); + else { + int plen=((struct tnode *)n)->pos; + t_key prf=MASK_PFX(n->key, plen); + seq_printf(seq, "key=%d.%d.%d.%d/%d\n", + prf >> 24, (prf >> 16) % 256, (prf >> 8) % 256, prf % 256, plen); + } + if (IS_LEAF(n)) { + struct leaf *l=(struct leaf *)n; + struct fib_alias *fa; + int i; + for (i=32; i>=0; i--) + if(find_leaf_info(&l->list, i)) { + + struct list_head *fa_head = get_fa_head(l, i); + + if(!fa_head) + continue; + + if(list_empty(fa_head)) + continue; + + putspace_seq(seq, indent+2); + seq_printf(seq, "{/%d...dumping}\n", i); + + + list_for_each_entry(fa, fa_head, fa_list) { + putspace_seq(seq, indent+2); + if (fa->fa_info->fib_nh == NULL) { + seq_printf(seq, "Error _fib_nh=NULL\n"); + continue; + } + if (fa->fa_info == NULL) { + seq_printf(seq, "Error fa_info=NULL\n"); + continue; + } + + seq_printf(seq, "{type=%d scope=%d TOS=%d}\n", + fa->fa_type, + fa->fa_scope, + fa->fa_tos); + } + } + } + else if (IS_TNODE(n)) { + struct tnode *tn=(struct tnode *)n; + putspace_seq(seq, indent); seq_printf(seq, "| "); + seq_printf(seq, "{key prefix=%08x/", tn->key&TKEY_GET_MASK(0, tn->pos)); + printbin_seq(seq, tkey_extract_bits(tn->key, 0, tn->pos), tn->pos); + seq_printf(seq, "}\n"); + putspace_seq(seq, indent); seq_printf(seq, "| "); + seq_printf(seq, "{pos=%d", tn->pos); + seq_printf(seq, " (skip=%d bits)", tn->pos - pend); + seq_printf(seq, " bits=%d (%u children)}\n", tn->bits, (1 << tn->bits)); + putspace_seq(seq, indent); seq_printf(seq, "| "); + seq_printf(seq, "{empty=%d full=%d}\n", tn->empty_children, tn->full_children); + } +} + +static void trie_dump_seq(struct seq_file *seq, struct trie *t) +{ + struct node *n=t->trie; + int cindex=0; + int indent=1; + int pend=0; + int depth = 0; + + read_lock(&fib_lock); + + seq_printf(seq, "------ trie_dump of t=%p ------\n", t); + if (n) { + printnode_seq(seq, indent, n, pend, cindex, 0); + if (IS_TNODE(n)) { + struct tnode *tn=(struct tnode *)n; + pend = tn->pos+tn->bits; + putspace_seq(seq, indent); seq_printf(seq, "\\--\n"); + indent += 3; + depth++; + + while (tn && cindex < (1 << tn->bits)) { + if (tn->child[cindex]) { + + /* Got a child */ + + printnode_seq(seq, indent, tn->child[cindex], pend, cindex, tn->bits); + if (IS_LEAF(tn->child[cindex])) { + cindex++; + + } + else { + /* + * New tnode. Decend one level + */ + + depth++; + n=tn->child[cindex]; + tn=(struct tnode *)n; + pend=tn->pos+tn->bits; + putspace_seq(seq, indent); seq_printf(seq, "\\--\n"); + indent+=3; + cindex=0; + } + } + else + cindex++; + + /* + * Test if we are done + */ + + while (cindex >= (1 << tn->bits)) { + + /* + * Move upwards and test for root + * pop off all traversed nodes + */ + + if (NODE_PARENT(tn) == NULL) { + tn = NULL; + n = NULL; + break; + } + else { + cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits); + tn = NODE_PARENT(tn); + cindex++; + n=(struct node *)tn; + pend=tn->pos+tn->bits; + indent-=3; + depth--; + } + } + } + } + else n = NULL; + } + else seq_printf(seq, "------ trie is empty\n"); + + read_unlock(&fib_lock); +} + +static struct trie_stat *trie_stat_new(void) +{ + struct trie_stat *s = kmalloc(sizeof(struct trie_stat), GFP_KERNEL); + int i; + + if(s) { + s->totdepth = 0; + s->maxdepth = 0; + s->tnodes = 0; + s->leaves = 0; + s->nullpointers = 0; + + for(i=0; i< MAX_CHILDS; i++) + s->nodesizes[i] = 0; + } + return s; +} + +static struct trie_stat *trie_collect_stats(struct trie *t) +{ + struct node *n=t->trie; + struct trie_stat *s = trie_stat_new(); + int cindex = 0; + int indent = 1; + int pend = 0; + int depth = 0; + + read_lock(&fib_lock); + + if (s) { + if (n) { + if (IS_TNODE(n)) { + struct tnode *tn = (struct tnode *)n; + pend=tn->pos+tn->bits; + indent += 3; + s->nodesizes[tn->bits]++; + depth++; + + while (tn && cindex < (1 << tn->bits)) { + if (tn->child[cindex]) { + /* Got a child */ + + if (IS_LEAF(tn->child[cindex])) { + cindex++; + + /* stats */ + if (depth > s->maxdepth) + s->maxdepth = depth; + s->totdepth += depth; + s->leaves++; + } + + else { + /* + * New tnode. Decend one level + */ + + s->tnodes++; + s->nodesizes[tn->bits]++; + depth++; + + n = tn->child[cindex]; + tn = (struct tnode *)n; + pend = tn->pos+tn->bits; + + indent += 3; + cindex = 0; + } + } + else { + cindex++; + s->nullpointers++; + } + + /* + * Test if we are done + */ + + while (cindex >= (1 << tn->bits)) { + + /* + * Move upwards and test for root + * pop off all traversed nodes + */ + + + if (NODE_PARENT(tn) == NULL) { + tn = NULL; + n = NULL; + break; + } + else { + cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits); + tn = NODE_PARENT(tn); + cindex++; + n = (struct node *)tn; + pend=tn->pos+tn->bits; + indent -= 3; + depth--; + } + } + } + } + else n = NULL; + } + } + + read_unlock(&fib_lock); + return s; +} + +#ifdef CONFIG_PROC_FS + +static struct fib_alias *fib_triestat_get_first(struct seq_file *seq) +{ + return NULL; +} + +static struct fib_alias *fib_triestat_get_next(struct seq_file *seq) +{ + return NULL; +} + +static void *fib_triestat_seq_start(struct seq_file *seq, loff_t *pos) +{ + void *v = NULL; + + if (ip_fib_main_table) + v = *pos ? fib_triestat_get_next(seq) : SEQ_START_TOKEN; + return v; +} + +static void *fib_triestat_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return v == SEQ_START_TOKEN ? fib_triestat_get_first(seq) : fib_triestat_get_next(seq); +} + +static void fib_triestat_seq_stop(struct seq_file *seq, void *v) +{ + +} + +/* + * This outputs /proc/net/fib_triestats + * + * It always works in backward compatibility mode. + * The format of the file is not supposed to be changed. + */ + +static void collect_and_show(struct trie *t, struct seq_file *seq) +{ + int bytes = 0; /* How many bytes are used, a ref is 4 bytes */ + int i, max, pointers; + struct trie_stat *stat; + int avdepth; + + stat = trie_collect_stats(t); + + bytes=0; + seq_printf(seq, "trie=%p\n", t); + + if (stat) { + if (stat->leaves) + avdepth=stat->totdepth*100 / stat->leaves; + else + avdepth=0; + seq_printf(seq, "Aver depth: %d.%02d\n", avdepth / 100, avdepth % 100 ); + seq_printf(seq, "Max depth: %4d\n", stat->maxdepth); + + seq_printf(seq, "Leaves: %d\n", stat->leaves); + bytes += sizeof(struct leaf) * stat->leaves; + seq_printf(seq, "Internal nodes: %d\n", stat->tnodes); + bytes += sizeof(struct tnode) * stat->tnodes; + + max = MAX_CHILDS-1; + + while (max >= 0 && stat->nodesizes[max] == 0) + max--; + pointers = 0; + + for (i = 1; i <= max; i++) + if (stat->nodesizes[i] != 0) { + seq_printf(seq, " %d: %d", i, stat->nodesizes[i]); + pointers += (1<nodesizes[i]; + } + seq_printf(seq, "\n"); + seq_printf(seq, "Pointers: %d\n", pointers); + bytes += sizeof(struct node *) * pointers; + seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers); + seq_printf(seq, "Total size: %d kB\n", bytes / 1024); + + kfree(stat); + } + +#ifdef CONFIG_IP_FIB_TRIE_STATS + seq_printf(seq, "Counters:\n---------\n"); + seq_printf(seq,"gets = %d\n", t->stats.gets); + seq_printf(seq,"backtracks = %d\n", t->stats.backtrack); + seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed); + seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss); + seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit); +#ifdef CLEAR_STATS + memset(&(t->stats), 0, sizeof(t->stats)); +#endif +#endif /* CONFIG_IP_FIB_TRIE_STATS */ +} + +static int fib_triestat_seq_show(struct seq_file *seq, void *v) +{ + char bf[128]; + + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n", + sizeof(struct leaf), sizeof(struct tnode)); + if (trie_local) + collect_and_show(trie_local, seq); + + if (trie_main) + collect_and_show(trie_main, seq); + } + else { + snprintf(bf, sizeof(bf), + "*\t%08X\t%08X", 200, 400); + + seq_printf(seq, "%-127s\n", bf); + } + return 0; +} + +static struct seq_operations fib_triestat_seq_ops = { + .start = fib_triestat_seq_start, + .next = fib_triestat_seq_next, + .stop = fib_triestat_seq_stop, + .show = fib_triestat_seq_show, +}; + +static int fib_triestat_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int rc = -ENOMEM; + + rc = seq_open(file, &fib_triestat_seq_ops); + if (rc) + goto out_kfree; + + seq = file->private_data; +out: + return rc; +out_kfree: + goto out; +} + +static struct file_operations fib_triestat_seq_fops = { + .owner = THIS_MODULE, + .open = fib_triestat_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +int __init fib_stat_proc_init(void) +{ + if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_seq_fops)) + return -ENOMEM; + return 0; +} + +void __init fib_stat_proc_exit(void) +{ + proc_net_remove("fib_triestat"); +} + +static struct fib_alias *fib_trie_get_first(struct seq_file *seq) +{ + return NULL; +} + +static struct fib_alias *fib_trie_get_next(struct seq_file *seq) +{ + return NULL; +} + +static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) +{ + void *v = NULL; + + if (ip_fib_main_table) + v = *pos ? fib_trie_get_next(seq) : SEQ_START_TOKEN; + return v; +} + +static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return v == SEQ_START_TOKEN ? fib_trie_get_first(seq) : fib_trie_get_next(seq); +} + +static void fib_trie_seq_stop(struct seq_file *seq, void *v) +{ + +} + +/* + * This outputs /proc/net/fib_trie. + * + * It always works in backward compatibility mode. + * The format of the file is not supposed to be changed. + */ + +static int fib_trie_seq_show(struct seq_file *seq, void *v) +{ + char bf[128]; + + if (v == SEQ_START_TOKEN) { + if (trie_local) + trie_dump_seq(seq, trie_local); + + if (trie_main) + trie_dump_seq(seq, trie_main); + } + + else { + snprintf(bf, sizeof(bf), + "*\t%08X\t%08X", 200, 400); + seq_printf(seq, "%-127s\n", bf); + } + + return 0; +} + +static struct seq_operations fib_trie_seq_ops = { + .start = fib_trie_seq_start, + .next = fib_trie_seq_next, + .stop = fib_trie_seq_stop, + .show = fib_trie_seq_show, +}; + +static int fib_trie_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int rc = -ENOMEM; + + rc = seq_open(file, &fib_trie_seq_ops); + if (rc) + goto out_kfree; + + seq = file->private_data; +out: + return rc; +out_kfree: + goto out; +} + +static struct file_operations fib_trie_seq_fops = { + .owner = THIS_MODULE, + .open = fib_trie_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +int __init fib_proc_init(void) +{ + if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_seq_fops)) + return -ENOMEM; + return 0; +} + +void __init fib_proc_exit(void) +{ + proc_net_remove("fib_trie"); +} + +#endif /* CONFIG_PROC_FS */ -- cgit v0.10.2 From 0d51aa80a9b1db43920c0770c3bb842dd823c005 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 21 Jun 2005 13:51:04 -0700 Subject: [IPV6]: V6 route events reported with wrong netlink PID and seq number Essentially netlink at the moment always reports a pid and sequence of 0 always for v6 route activities. To understand the repurcassions of this look at: http://lists.quagga.net/pipermail/quagga-dev/2005-June/003507.html While fixing this, i took the liberty to resolve the outstanding issue of IPV6 routes inserted via ioctls to have the correct pids as well. This patch tries to behave as close as possible to the v4 routes i.e maintains whatever PID the socket issuing the command owns as opposed to the process. That made the patch a little bulky. I have tested against both netlink derived utility to add/del routes as well as ioctl derived one. The Quagga folks have tested against quagga. This fixes the problem and so far hasnt been detected to introduce any new issues. Signed-off-by: Jamal Hadi Salim Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 3199045..a66e9de 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -167,14 +167,17 @@ extern int fib6_walk_continue(struct fib6_walker_t *w); extern int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh, - void *rtattr); + void *rtattr, + struct netlink_skb_parms *req); extern int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, - void *rtattr); + void *rtattr, + struct netlink_skb_parms *req); extern void inet6_rt_notify(int event, struct rt6_info *rt, - struct nlmsghdr *nlh); + struct nlmsghdr *nlh, + struct netlink_skb_parms *req); extern void fib6_run_gc(unsigned long dummy); diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index d5d1dd1..f920706 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -41,13 +41,16 @@ extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg); extern int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *, - void *rtattr); + void *rtattr, + struct netlink_skb_parms *req); extern int ip6_ins_rt(struct rt6_info *, struct nlmsghdr *, - void *rtattr); + void *rtattr, + struct netlink_skb_parms *req); extern int ip6_del_rt(struct rt6_info *, struct nlmsghdr *, - void *rtattr); + void *rtattr, + struct netlink_skb_parms *req); extern int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 47a30c3..14f5c53 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -695,7 +695,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (onlink == 0) { - ip6_del_rt(rt, NULL, NULL); + ip6_del_rt(rt, NULL, NULL, NULL); rt = NULL; } else if (!(rt->rt6i_flags & RTF_EXPIRES)) { rt->rt6i_expires = expires; @@ -1340,7 +1340,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT)) rtmsg.rtmsg_flags |= RTF_NONEXTHOP; - ip6_route_add(&rtmsg, NULL, NULL); + ip6_route_add(&rtmsg, NULL, NULL, NULL); } /* Create "default" multicast route to the interface */ @@ -1357,7 +1357,7 @@ static void addrconf_add_mroute(struct net_device *dev) rtmsg.rtmsg_ifindex = dev->ifindex; rtmsg.rtmsg_flags = RTF_UP; rtmsg.rtmsg_type = RTMSG_NEWROUTE; - ip6_route_add(&rtmsg, NULL, NULL); + ip6_route_add(&rtmsg, NULL, NULL, NULL); } static void sit_route_add(struct net_device *dev) @@ -1374,7 +1374,7 @@ static void sit_route_add(struct net_device *dev) rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP; rtmsg.rtmsg_ifindex = dev->ifindex; - ip6_route_add(&rtmsg, NULL, NULL); + ip6_route_add(&rtmsg, NULL, NULL, NULL); } static void addrconf_add_lroute(struct net_device *dev) @@ -1467,7 +1467,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (rt->rt6i_flags&RTF_EXPIRES) { if (valid_lft == 0) { - ip6_del_rt(rt, NULL, NULL); + ip6_del_rt(rt, NULL, NULL, NULL); rt = NULL; } else { rt->rt6i_expires = rt_expires; @@ -3094,7 +3094,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) switch (event) { case RTM_NEWADDR: dst_hold(&ifp->rt->u.dst); - if (ip6_ins_rt(ifp->rt, NULL, NULL)) + if (ip6_ins_rt(ifp->rt, NULL, NULL, NULL)) dst_release(&ifp->rt->u.dst); if (ifp->idev->cnf.forwarding) addrconf_join_anycast(ifp); @@ -3104,7 +3104,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) addrconf_leave_anycast(ifp); addrconf_leave_solict(ifp->idev, &ifp->addr); dst_hold(&ifp->rt->u.dst); - if (ip6_del_rt(ifp->rt, NULL, NULL)) + if (ip6_del_rt(ifp->rt, NULL, NULL, NULL)) dst_free(&ifp->rt->u.dst); else dst_release(&ifp->rt->u.dst); diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 5d22ca3..6b72940 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -337,7 +337,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) write_unlock_bh(&idev->lock); dst_hold(&rt->u.dst); - if (ip6_ins_rt(rt, NULL, NULL)) + if (ip6_ins_rt(rt, NULL, NULL, NULL)) dst_release(&rt->u.dst); addrconf_join_solict(dev, &aca->aca_addr); @@ -380,7 +380,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr) addrconf_leave_solict(idev, &aca->aca_addr); dst_hold(&aca->aca_rt->u.dst); - if (ip6_del_rt(aca->aca_rt, NULL, NULL)) + if (ip6_del_rt(aca->aca_rt, NULL, NULL, NULL)) dst_free(&aca->aca_rt->u.dst); else dst_release(&aca->aca_rt->u.dst); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 405740b..1b354aa 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -394,7 +394,7 @@ insert_above: */ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, - struct nlmsghdr *nlh) + struct nlmsghdr *nlh, struct netlink_skb_parms *req) { struct rt6_info *iter = NULL; struct rt6_info **ins; @@ -449,7 +449,7 @@ out: *ins = rt; rt->rt6i_node = fn; atomic_inc(&rt->rt6i_ref); - inet6_rt_notify(RTM_NEWROUTE, rt, nlh); + inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req); rt6_stats.fib_rt_entries++; if ((fn->fn_flags & RTN_RTINFO) == 0) { @@ -479,7 +479,8 @@ void fib6_force_start_gc(void) * with source addr info in sub-trees */ -int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) +int fib6_add(struct fib6_node *root, struct rt6_info *rt, + struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) { struct fib6_node *fn; int err = -ENOMEM; @@ -552,7 +553,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh, } #endif - err = fib6_add_rt2node(fn, rt, nlh); + err = fib6_add_rt2node(fn, rt, nlh, req); if (err == 0) { fib6_start_gc(rt); @@ -859,7 +860,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) } static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, - struct nlmsghdr *nlh, void *_rtattr) + struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) { struct fib6_walker_t *w; struct rt6_info *rt = *rtp; @@ -915,11 +916,11 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, if (atomic_read(&rt->rt6i_ref) != 1) BUG(); } - inet6_rt_notify(RTM_DELROUTE, rt, nlh); + inet6_rt_notify(RTM_DELROUTE, rt, nlh, req); rt6_release(rt); } -int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) +int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) { struct fib6_node *fn = rt->rt6i_node; struct rt6_info **rtp; @@ -944,7 +945,7 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { if (*rtp == rt) { - fib6_del_route(fn, rtp, nlh, _rtattr); + fib6_del_route(fn, rtp, nlh, _rtattr, req); return 0; } } @@ -1073,7 +1074,7 @@ static int fib6_clean_node(struct fib6_walker_t *w) res = c->func(rt, c->arg); if (res < 0) { w->leaf = rt; - res = fib6_del(rt, NULL, NULL); + res = fib6_del(rt, NULL, NULL, NULL); if (res) { #if RT6_DEBUG >= 2 printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7c291f4..7ae72d4 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -955,7 +955,7 @@ static void ndisc_recv_na(struct sk_buff *skb) struct rt6_info *rt; rt = rt6_get_dflt_router(saddr, dev); if (rt) - ip6_del_rt(rt, NULL, NULL); + ip6_del_rt(rt, NULL, NULL, NULL); } out: @@ -1096,7 +1096,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) if (rt && lifetime == 0) { neigh_clone(neigh); - ip6_del_rt(rt, NULL, NULL); + ip6_del_rt(rt, NULL, NULL, NULL); rt = NULL; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 1f5b226..878789b 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -384,12 +384,13 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, be destroyed. */ -int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) +int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, + void *_rtattr, struct netlink_skb_parms *req) { int err; write_lock_bh(&rt6_lock); - err = fib6_add(&ip6_routing_table, rt, nlh, _rtattr); + err = fib6_add(&ip6_routing_table, rt, nlh, _rtattr, req); write_unlock_bh(&rt6_lock); return err; @@ -400,7 +401,7 @@ int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) */ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, - struct in6_addr *saddr) + struct in6_addr *saddr, struct netlink_skb_parms *req) { int err; struct rt6_info *rt; @@ -432,7 +433,7 @@ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, dst_hold(&rt->u.dst); - err = ip6_ins_rt(rt, NULL, NULL); + err = ip6_ins_rt(rt, NULL, NULL, req); if (err == 0) return rt; @@ -491,7 +492,8 @@ restart: read_unlock_bh(&rt6_lock); nrt = rt6_cow(rt, &skb->nh.ipv6h->daddr, - &skb->nh.ipv6h->saddr); + &skb->nh.ipv6h->saddr, + &NETLINK_CB(skb)); dst_release(&rt->u.dst); rt = nrt; @@ -551,7 +553,7 @@ restart: dst_hold(&rt->u.dst); read_unlock_bh(&rt6_lock); - nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src); + nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src, NULL); dst_release(&rt->u.dst); rt = nrt; @@ -598,7 +600,7 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) if (rt) { if (rt->rt6i_flags & RTF_CACHE) - ip6_del_rt(rt, NULL, NULL); + ip6_del_rt(rt, NULL, NULL, NULL); else dst_release(dst); } @@ -787,7 +789,8 @@ int ipv6_get_hoplimit(struct net_device *dev) * */ -int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr) +int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, + void *_rtattr, struct netlink_skb_parms *req) { int err; struct rtmsg *r; @@ -974,7 +977,7 @@ install_route: rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); rt->u.dst.dev = dev; rt->rt6i_idev = idev; - return ip6_ins_rt(rt, nlh, _rtattr); + return ip6_ins_rt(rt, nlh, _rtattr, req); out: if (dev) @@ -986,7 +989,7 @@ out: return err; } -int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) +int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) { int err; @@ -994,7 +997,7 @@ int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) rt6_reset_dflt_pointer(NULL); - err = fib6_del(rt, nlh, _rtattr); + err = fib6_del(rt, nlh, _rtattr, req); dst_release(&rt->u.dst); write_unlock_bh(&rt6_lock); @@ -1002,7 +1005,7 @@ int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) return err; } -static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr) +static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) { struct fib6_node *fn; struct rt6_info *rt; @@ -1029,7 +1032,7 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_r dst_hold(&rt->u.dst); read_unlock_bh(&rt6_lock); - return ip6_del_rt(rt, nlh, _rtattr); + return ip6_del_rt(rt, nlh, _rtattr, req); } } read_unlock_bh(&rt6_lock); @@ -1136,11 +1139,11 @@ source_ok: nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst)); - if (ip6_ins_rt(nrt, NULL, NULL)) + if (ip6_ins_rt(nrt, NULL, NULL, NULL)) goto out; if (rt->rt6i_flags&RTF_CACHE) { - ip6_del_rt(rt, NULL, NULL); + ip6_del_rt(rt, NULL, NULL, NULL); return; } @@ -1204,7 +1207,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, 2. It is gatewayed route or NONEXTHOP route. Action: clone it. */ if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { - nrt = rt6_cow(rt, daddr, saddr); + nrt = rt6_cow(rt, daddr, saddr, NULL); if (!nrt->u.dst.error) { nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; if (allfrag) @@ -1232,7 +1235,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; if (allfrag) nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; - ip6_ins_rt(nrt, NULL, NULL); + ip6_ins_rt(nrt, NULL, NULL, NULL); } out: @@ -1305,7 +1308,7 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, rtmsg.rtmsg_ifindex = dev->ifindex; - ip6_route_add(&rtmsg, NULL, NULL); + ip6_route_add(&rtmsg, NULL, NULL, NULL); return rt6_get_dflt_router(gwaddr, dev); } @@ -1323,7 +1326,7 @@ restart: read_unlock_bh(&rt6_lock); - ip6_del_rt(rt, NULL, NULL); + ip6_del_rt(rt, NULL, NULL, NULL); goto restart; } @@ -1349,10 +1352,10 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg) rtnl_lock(); switch (cmd) { case SIOCADDRT: - err = ip6_route_add(&rtmsg, NULL, NULL); + err = ip6_route_add(&rtmsg, NULL, NULL, NULL); break; case SIOCDELRT: - err = ip6_route_del(&rtmsg, NULL, NULL); + err = ip6_route_del(&rtmsg, NULL, NULL, NULL); break; default: err = -EINVAL; @@ -1546,7 +1549,7 @@ int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) return -EINVAL; - return ip6_route_del(&rtmsg, nlh, arg); + return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb)); } int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) @@ -1556,7 +1559,7 @@ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) return -EINVAL; - return ip6_route_add(&rtmsg, nlh, arg); + return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb)); } struct rt6_rtnl_dump_arg @@ -1566,12 +1569,9 @@ struct rt6_rtnl_dump_arg }; static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, - struct in6_addr *dst, - struct in6_addr *src, - int iif, - int type, u32 pid, u32 seq, - struct nlmsghdr *in_nlh, int prefix, - unsigned int flags) + struct in6_addr *dst, struct in6_addr *src, + int iif, int type, u32 pid, u32 seq, + int prefix, unsigned int flags) { struct rtmsg *rtm; struct nlmsghdr *nlh; @@ -1585,10 +1585,6 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, } } - if (!pid && in_nlh) { - pid = in_nlh->nlmsg_pid; - } - nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*rtm), flags); rtm = NLMSG_DATA(nlh); rtm->rtm_family = AF_INET6; @@ -1675,7 +1671,7 @@ static int rt6_dump_route(struct rt6_info *rt, void *p_arg) return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq, - NULL, prefix, NLM_F_MULTI); + prefix, NLM_F_MULTI); } static int fib6_dump_node(struct fib6_walker_t *w) @@ -1823,7 +1819,7 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) &fl.fl6_dst, &fl.fl6_src, iif, RTM_NEWROUTE, NETLINK_CB(in_skb).pid, - nlh->nlmsg_seq, nlh, 0, 0); + nlh->nlmsg_seq, 0, 0); if (err < 0) { err = -EMSGSIZE; goto out_free; @@ -1839,17 +1835,25 @@ out_free: goto out; } -void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh) +void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh, + struct netlink_skb_parms *req) { struct sk_buff *skb; int size = NLMSG_SPACE(sizeof(struct rtmsg)+256); + u32 pid = current->pid; + u32 seq = 0; + if (req) + pid = req->pid; + if (nlh) + seq = nlh->nlmsg_seq; + skb = alloc_skb(size, gfp_any()); if (!skb) { netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS); return; } - if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0, nlh, 0, 0) < 0) { + if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0) < 0) { kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL); return; -- cgit v0.10.2 From c9e3e8b6958e02230079e6817862ea2968509866 Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Tue, 21 Jun 2005 13:58:25 -0700 Subject: [IPV6]: multicast join and misc Here is a simplified version of the patch to fix a bug in IPv6 multicasting. It: 1) adds existence check & EADDRINUSE error for regular joins 2) adds an exception for EADDRINUSE in the source-specific multicast join (where a prior join is ok) 3) adds a missing/needed read_lock on sock_mc_list; would've raced with destroying the socket on interface down without 4) adds a "leave group" in the (INCLUDE, empty) source filter case. This frees unneeded socket buffer memory, but also prevents an inappropriate interaction among the 8 socket options that mess with this. Some would fail as if in the group when you aren't really. Item #4 had a locking bug in the last version of this patch; rather than removing the idev->lock read lock only, I've simplified it to remove all lock state in the path and treat it as a direct "leave group" call for the (INCLUDE,empty) case it covers. Tested on an MP machine. :-) Much thanks to HoerdtMickael who reported the original bug. Signed-off-by: David L Stevens Signed-off-by: David S. Miller diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 279ab86..f3ef4c3 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -423,11 +423,12 @@ done: psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; retv = ipv6_sock_mc_join(sk, greqs.gsr_interface, &psin6->sin6_addr); - if (retv) + /* prior join w/ different source is ok */ + if (retv && retv != -EADDRINUSE) break; omode = MCAST_INCLUDE; add = 1; - } else /*IP_DROP_SOURCE_MEMBERSHIP */ { + } else /* MCAST_LEAVE_SOURCE_GROUP */ { omode = MCAST_INCLUDE; add = 0; } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 393b6e6..c0ca92e 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -188,6 +188,16 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) if (!ipv6_addr_is_multicast(addr)) return -EINVAL; + read_lock_bh(&ipv6_sk_mc_lock); + for (mc_lst=np->ipv6_mc_list; mc_lst; mc_lst=mc_lst->next) { + if ((ifindex == 0 || mc_lst->ifindex == ifindex) && + ipv6_addr_equal(&mc_lst->addr, addr)) { + read_unlock_bh(&ipv6_sk_mc_lock); + return -EADDRINUSE; + } + } + read_unlock_bh(&ipv6_sk_mc_lock); + mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL); if (mc_lst == NULL) @@ -349,6 +359,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ip6_sf_socklist *psl; int i, j, rv; + int leavegroup = 0; int err; if (pgsr->gsr_group.ss_family != AF_INET6 || @@ -368,6 +379,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, err = -EADDRNOTAVAIL; + read_lock_bh(&ipv6_sk_mc_lock); for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) continue; @@ -401,6 +413,12 @@ int ip6_mc_source(int add, int omode, struct sock *sk, if (rv) /* source not found */ goto done; + /* special case - (INCLUDE, empty) == LEAVE_GROUP */ + if (psl->sl_count == 1 && omode == MCAST_INCLUDE) { + leavegroup = 1; + goto done; + } + /* update the interface filter */ ip6_mc_del_src(idev, group, omode, 1, source, 1); @@ -453,9 +471,12 @@ int ip6_mc_source(int add, int omode, struct sock *sk, /* update the interface list */ ip6_mc_add_src(idev, group, omode, 1, source, 1); done: + read_unlock_bh(&ipv6_sk_mc_lock); read_unlock_bh(&idev->lock); in6_dev_put(idev); dev_put(dev); + if (leavegroup) + return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group); return err; } -- cgit v0.10.2 From 95dccdfe29a76c513e29f88f366612d7570adab3 Mon Sep 17 00:00:00 2001 From: Greg Edwards Date: Tue, 21 Jun 2005 10:43:00 -0700 Subject: [IA64] refresh arch/ia64/defconfig Refresh arch/ia64/defconfig, as it was getting a bit stale. The only manual changes I made were: CONFIG_SCSI_SATA=y needed for some Altix base I/O cards CONFIG_SCSI_SATA_VITESSE=y CONFIG_DM_MULTIPATH=m the rest are already modules CONFIG_FUSION_SPI=y new driver breakout CONFIG_FUSION_FC=m CONFIG_SGI_TIOCX=y enable some other SGI drivers CONFIG_SGI_MBCS=m CONFIG_AGP_SGI_TIOCA=m Boot tested on Altix, HP rx2600 and Intel Tiger Signed-off-by: Greg Edwards Signed-off-by: Tony Luck diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig index 7539e83..2aea0f9 100644 --- a/arch/ia64/defconfig +++ b/arch/ia64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10 -# Thu Jan 6 11:13:13 2005 +# Linux kernel version: 2.6.12 +# Tue Jun 21 11:30:42 2005 # # @@ -10,6 +10,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -21,24 +22,27 @@ CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=20 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +# CONFIG_CPUSETS is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y CONFIG_CC_ALIGN_FUNCTIONS=0 CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -63,9 +67,11 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_TIME_INTERPOLATION=y CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_IA64_GENERIC=y # CONFIG_IA64_DIG is not set # CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_HP_ZX1_SWIOTLB is not set # CONFIG_IA64_SGI_SN2 is not set # CONFIG_IA64_HP_SIM is not set # CONFIG_ITANIUM is not set @@ -77,6 +83,7 @@ CONFIG_IA64_PAGE_SIZE_16KB=y CONFIG_IA64_L1_CACHE_SHIFT=7 CONFIG_NUMA=y CONFIG_VIRTUAL_MEM_MAP=y +CONFIG_HOLES_IN_ZONE=y CONFIG_DISCONTIGMEM=y CONFIG_IA64_CYCLONE=y CONFIG_IOSAPIC=y @@ -84,6 +91,7 @@ CONFIG_FORCE_MAX_ZONEORDER=18 CONFIG_SMP=y CONFIG_NR_CPUS=512 CONFIG_HOTPLUG_CPU=y +# CONFIG_SCHED_SMT is not set # CONFIG_PREEMPT is not set CONFIG_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y @@ -135,6 +143,7 @@ CONFIG_PCI_DOMAINS=y # CONFIG_PCI_MSI is not set CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set # # PCI Hotplug Support @@ -144,7 +153,6 @@ CONFIG_HOTPLUG_PCI=m CONFIG_HOTPLUG_PCI_ACPI=m # CONFIG_HOTPLUG_PCI_ACPI_IBM is not set # CONFIG_HOTPLUG_PCI_CPCI is not set -# CONFIG_HOTPLUG_PCI_PCIE is not set # CONFIG_HOTPLUG_PCI_SHPC is not set # @@ -153,10 +161,6 @@ CONFIG_HOTPLUG_PCI_ACPI=m # CONFIG_PCCARD is not set # -# PC-card bridges -# - -# # Device Drivers # @@ -190,6 +194,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m @@ -209,6 +214,7 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set # # ATA/ATAPI/MFM/RLL support @@ -283,6 +289,7 @@ CONFIG_CHR_DEV_ST=m CONFIG_BLK_DEV_SR=m # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -310,13 +317,21 @@ CONFIG_SCSI_FC_ATTRS=y # CONFIG_SCSI_AIC79XX is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set -# CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_BUSLOGIC is not set +CONFIG_SCSI_SATA=y +# CONFIG_SCSI_SATA_AHCI is not set +# CONFIG_SCSI_SATA_SVW is not set +# CONFIG_SCSI_ATA_PIIX is not set +# CONFIG_SCSI_SATA_NV is not set +# CONFIG_SCSI_SATA_PROMISE is not set +# CONFIG_SCSI_SATA_QSTOR is not set +# CONFIG_SCSI_SATA_SX4 is not set +# CONFIG_SCSI_SATA_SIL is not set +# CONFIG_SCSI_SATA_SIS is not set +# CONFIG_SCSI_SATA_ULI is not set +# CONFIG_SCSI_SATA_VIA is not set +CONFIG_SCSI_SATA_VITESSE=y # CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set @@ -326,7 +341,6 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_QLOGIC_ISP is not set CONFIG_SCSI_QLOGIC_FC=y # CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set CONFIG_SCSI_QLOGIC_1280=y @@ -337,6 +351,7 @@ CONFIG_SCSI_QLA22XX=m CONFIG_SCSI_QLA2300=m CONFIG_SCSI_QLA2322=m # CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set @@ -359,12 +374,16 @@ CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +# CONFIG_DM_MULTIPATH_EMC is not set # # Fusion MPT device support # CONFIG_FUSION=y -CONFIG_FUSION_MAX_SGE=40 +CONFIG_FUSION_SPI=y +CONFIG_FUSION_FC=m +CONFIG_FUSION_MAX_SGE=128 # CONFIG_FUSION_CTL is not set # @@ -387,7 +406,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK_DEV=y CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -447,7 +465,6 @@ CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set # # ARCnet devices @@ -484,9 +501,7 @@ CONFIG_NET_PCI=y # CONFIG_FORCEDETH is not set # CONFIG_DGRS is not set CONFIG_EEPRO100=m -# CONFIG_EEPRO100_PIO is not set CONFIG_E100=m -# CONFIG_E100_NAPI is not set # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set @@ -508,9 +523,11 @@ CONFIG_E1000=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SKGE is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=y +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) @@ -568,25 +585,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers -# -CONFIG_GAMEPORT=m -CONFIG_SOUND_GAMEPORT=m -# CONFIG_GAMEPORT_NS558 is not set -# CONFIG_GAMEPORT_L4 is not set -# CONFIG_GAMEPORT_EMU10K1 is not set -# CONFIG_GAMEPORT_VORTEX is not set -# CONFIG_GAMEPORT_FM801 is not set -# CONFIG_GAMEPORT_CS461x is not set -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -# CONFIG_SERIO_SERPORT is not set -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PCIPS2 is not set -CONFIG_SERIO_LIBPS2=y -# CONFIG_SERIO_RAW is not set - -# # Input Device Drivers # CONFIG_INPUT_KEYBOARD=y @@ -604,6 +602,23 @@ CONFIG_MOUSE_PS2=y # CONFIG_INPUT_MISC is not set # +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +CONFIG_GAMEPORT=m +# CONFIG_GAMEPORT_NS558 is not set +# CONFIG_GAMEPORT_L4 is not set +# CONFIG_GAMEPORT_EMU10K1 is not set +# CONFIG_GAMEPORT_VORTEX is not set +# CONFIG_GAMEPORT_FM801 is not set +# CONFIG_GAMEPORT_CS461X is not set + +# # Character devices # CONFIG_VT=y @@ -613,11 +628,15 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_ROCKETPORT is not set # CONFIG_CYCLADES is not set # CONFIG_MOXA_SMARTIO is not set -# CONFIG_SYNCLINK is not set +# CONFIG_ISI is not set # CONFIG_SYNCLINKMP is not set # CONFIG_N_HDLC is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set # CONFIG_STALDRV is not set CONFIG_SGI_SNSC=y +CONFIG_SGI_TIOCX=y +CONFIG_SGI_MBCS=m # # Serial drivers @@ -638,6 +657,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_SGI_L1_CONSOLE=y +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -663,6 +683,7 @@ CONFIG_EFI_RTC=y CONFIG_AGP=m CONFIG_AGP_I460=m CONFIG_AGP_HP_ZX1=m +CONFIG_AGP_SGI_TIOCA=m CONFIG_DRM=m CONFIG_DRM_TDFX=m CONFIG_DRM_R128=m @@ -674,9 +695,15 @@ CONFIG_HPET=y # CONFIG_HPET_RTC_IRQ is not set CONFIG_HPET_MMAP=y CONFIG_MAX_RAW_DEVS=256 +# CONFIG_HANGCHECK_TIMER is not set CONFIG_MMTIMER=y # +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# # I2C support # # CONFIG_I2C is not set @@ -760,6 +787,8 @@ CONFIG_SND_CS46XX=m CONFIG_SND_CS46XX_NEW_DSP=y CONFIG_SND_CS4281=m CONFIG_SND_EMU10K1=m +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_CA0106 is not set # CONFIG_SND_KORG1212 is not set # CONFIG_SND_MIXART is not set # CONFIG_SND_NM256 is not set @@ -784,13 +813,14 @@ CONFIG_SND_FM801=m # CONFIG_SND_INTEL8X0M is not set # CONFIG_SND_SONICVIBES is not set # CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set # CONFIG_SND_VX222 is not set +# CONFIG_SND_HDA_INTEL is not set # # USB devices # # CONFIG_SND_USB_AUDIO is not set -# CONFIG_SND_USB_USX2Y is not set # # Open Sound System @@ -800,6 +830,8 @@ CONFIG_SND_FM801=m # # USB support # +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB=m # CONFIG_USB_DEBUG is not set @@ -811,8 +843,6 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_SUSPEND is not set # CONFIG_USB_OTG is not set -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB_ARCH_HAS_OHCI=y # # USB Host Controller Drivers @@ -821,6 +851,8 @@ CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y CONFIG_USB_UHCI_HCD=m # CONFIG_USB_SL811_HCD is not set @@ -838,12 +870,11 @@ CONFIG_USB_UHCI_HCD=m # CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_RW_DETECT is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_USBAT is not set # CONFIG_USB_STORAGE_SDDR09 is not set # CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set @@ -893,6 +924,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set # CONFIG_USB_USBNET is not set +CONFIG_USB_MON=m # # USB port drivers @@ -908,7 +940,6 @@ CONFIG_USB_HIDINPUT=y # # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set -# CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set @@ -917,6 +948,8 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_CYTHERM is not set # CONFIG_USB_PHIDGETKIT is not set # CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_SISUSBVGA is not set # CONFIG_USB_TEST is not set # @@ -964,7 +997,12 @@ CONFIG_REISERFS_FS_POSIX_ACL=y CONFIG_REISERFS_FS_SECURITY=y # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y + +# +# XFS support +# CONFIG_XFS_FS=y +CONFIG_XFS_EXPORT=y # CONFIG_XFS_RT is not set # CONFIG_XFS_QUOTA is not set # CONFIG_XFS_SECURITY is not set @@ -1042,7 +1080,7 @@ CONFIG_NFSD_V4=y CONFIG_NFSD_TCP=y CONFIG_LOCKD=m CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=m +CONFIG_EXPORTFS=y CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m @@ -1128,6 +1166,8 @@ CONFIG_NLS_UTF8=m # CONFIG_CRC_CCITT is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y # # HP Simulator drivers @@ -1144,14 +1184,17 @@ CONFIG_CRC32=y # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_LOG_BUF_SHIFT=20 # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_FS is not set CONFIG_IA64_GRANULE_16MB=y # CONFIG_IA64_GRANULE_64MB is not set # CONFIG_IA64_PRINT_HAZARDS is not set @@ -1178,6 +1221,7 @@ CONFIG_CRYPTO_MD5=m # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set CONFIG_CRYPTO_DES=m # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set -- cgit v0.10.2 From e45b1be8bcb3643808975a426fa3e201a2588e87 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 21 Jun 2005 14:01:30 -0700 Subject: [NETFILTER]: Kill lockhelp.h Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h index d84be02..694aec9 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_core.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h @@ -1,7 +1,6 @@ #ifndef _IP_CONNTRACK_CORE_H #define _IP_CONNTRACK_CORE_H #include -#include /* This header is used to share core functionality between the standalone connection tracking module, and the compatibility layer's use @@ -47,6 +46,6 @@ static inline int ip_conntrack_confirm(struct sk_buff **pskb) extern struct list_head *ip_conntrack_hash; extern struct list_head ip_conntrack_expect_list; -DECLARE_RWLOCK_EXTERN(ip_conntrack_lock); +extern rwlock_t ip_conntrack_lock; #endif /* _IP_CONNTRACK_CORE_H */ diff --git a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h index 2b72b86..e201ec6 100644 --- a/include/linux/netfilter_ipv4/ip_nat.h +++ b/include/linux/netfilter_ipv4/ip_nat.h @@ -50,10 +50,9 @@ struct ip_nat_multi_range_compat #ifdef __KERNEL__ #include -#include /* Protects NAT hash tables, and NAT-private part of conntracks. */ -DECLARE_RWLOCK_EXTERN(ip_nat_lock); +extern rwlock_t ip_nat_lock; /* The structure embedded in the conntrack structure. */ struct ip_nat_info diff --git a/include/linux/netfilter_ipv4/listhelp.h b/include/linux/netfilter_ipv4/listhelp.h index f2ae7c5..360429f 100644 --- a/include/linux/netfilter_ipv4/listhelp.h +++ b/include/linux/netfilter_ipv4/listhelp.h @@ -2,7 +2,6 @@ #define _LISTHELP_H #include #include -#include /* Header to do more comprehensive job than linux/list.h; assume list is first entry in structure. */ diff --git a/include/linux/netfilter_ipv4/lockhelp.h b/include/linux/netfilter_ipv4/lockhelp.h deleted file mode 100644 index a328863..0000000 --- a/include/linux/netfilter_ipv4/lockhelp.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef _LOCKHELP_H -#define _LOCKHELP_H -#include - -#include -#include -#include -#include - -/* Header to do help in lock debugging. */ - -#ifdef CONFIG_NETFILTER_DEBUG -struct spinlock_debug -{ - spinlock_t l; - atomic_t locked_by; -}; - -struct rwlock_debug -{ - rwlock_t l; - long read_locked_map; - long write_locked_map; -}; - -#define DECLARE_LOCK(l) \ -struct spinlock_debug l = { SPIN_LOCK_UNLOCKED, ATOMIC_INIT(-1) } -#define DECLARE_LOCK_EXTERN(l) \ -extern struct spinlock_debug l -#define DECLARE_RWLOCK(l) \ -struct rwlock_debug l = { RW_LOCK_UNLOCKED, 0, 0 } -#define DECLARE_RWLOCK_EXTERN(l) \ -extern struct rwlock_debug l - -#define MUST_BE_LOCKED(l) \ -do { if (atomic_read(&(l)->locked_by) != smp_processor_id()) \ - printk("ASSERT %s:%u %s unlocked\n", __FILE__, __LINE__, #l); \ -} while(0) - -#define MUST_BE_UNLOCKED(l) \ -do { if (atomic_read(&(l)->locked_by) == smp_processor_id()) \ - printk("ASSERT %s:%u %s locked\n", __FILE__, __LINE__, #l); \ -} while(0) - -/* Write locked OK as well. */ -#define MUST_BE_READ_LOCKED(l) \ -do { if (!((l)->read_locked_map & (1UL << smp_processor_id())) \ - && !((l)->write_locked_map & (1UL << smp_processor_id()))) \ - printk("ASSERT %s:%u %s not readlocked\n", __FILE__, __LINE__, #l); \ -} while(0) - -#define MUST_BE_WRITE_LOCKED(l) \ -do { if (!((l)->write_locked_map & (1UL << smp_processor_id()))) \ - printk("ASSERT %s:%u %s not writelocked\n", __FILE__, __LINE__, #l); \ -} while(0) - -#define MUST_BE_READ_WRITE_UNLOCKED(l) \ -do { if ((l)->read_locked_map & (1UL << smp_processor_id())) \ - printk("ASSERT %s:%u %s readlocked\n", __FILE__, __LINE__, #l); \ - else if ((l)->write_locked_map & (1UL << smp_processor_id())) \ - printk("ASSERT %s:%u %s writelocked\n", __FILE__, __LINE__, #l); \ -} while(0) - -#define LOCK_BH(lk) \ -do { \ - MUST_BE_UNLOCKED(lk); \ - spin_lock_bh(&(lk)->l); \ - atomic_set(&(lk)->locked_by, smp_processor_id()); \ -} while(0) - -#define UNLOCK_BH(lk) \ -do { \ - MUST_BE_LOCKED(lk); \ - atomic_set(&(lk)->locked_by, -1); \ - spin_unlock_bh(&(lk)->l); \ -} while(0) - -#define READ_LOCK(lk) \ -do { \ - MUST_BE_READ_WRITE_UNLOCKED(lk); \ - read_lock_bh(&(lk)->l); \ - set_bit(smp_processor_id(), &(lk)->read_locked_map); \ -} while(0) - -#define WRITE_LOCK(lk) \ -do { \ - MUST_BE_READ_WRITE_UNLOCKED(lk); \ - write_lock_bh(&(lk)->l); \ - set_bit(smp_processor_id(), &(lk)->write_locked_map); \ -} while(0) - -#define READ_UNLOCK(lk) \ -do { \ - if (!((lk)->read_locked_map & (1UL << smp_processor_id()))) \ - printk("ASSERT: %s:%u %s not readlocked\n", \ - __FILE__, __LINE__, #lk); \ - clear_bit(smp_processor_id(), &(lk)->read_locked_map); \ - read_unlock_bh(&(lk)->l); \ -} while(0) - -#define WRITE_UNLOCK(lk) \ -do { \ - MUST_BE_WRITE_LOCKED(lk); \ - clear_bit(smp_processor_id(), &(lk)->write_locked_map); \ - write_unlock_bh(&(lk)->l); \ -} while(0) - -#else -#define DECLARE_LOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED -#define DECLARE_LOCK_EXTERN(l) extern spinlock_t l -#define DECLARE_RWLOCK(l) rwlock_t l = RW_LOCK_UNLOCKED -#define DECLARE_RWLOCK_EXTERN(l) extern rwlock_t l - -#define MUST_BE_LOCKED(l) -#define MUST_BE_UNLOCKED(l) -#define MUST_BE_READ_LOCKED(l) -#define MUST_BE_WRITE_LOCKED(l) -#define MUST_BE_READ_WRITE_UNLOCKED(l) - -#define LOCK_BH(l) spin_lock_bh(l) -#define UNLOCK_BH(l) spin_unlock_bh(l) - -#define READ_LOCK(l) read_lock_bh(l) -#define WRITE_LOCK(l) write_lock_bh(l) -#define READ_UNLOCK(l) read_unlock_bh(l) -#define WRITE_UNLOCK(l) write_unlock_bh(l) -#endif /*CONFIG_NETFILTER_DEBUG*/ - -#endif /* _LOCKHELP_H */ diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index df79f5e..fa16342 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -60,7 +60,6 @@ static DECLARE_MUTEX(arpt_mutex); #define ASSERT_READ_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0) #define ASSERT_WRITE_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0) -#include #include struct arpt_table_info { diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index 3dbddd0..a78a320 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c @@ -26,7 +26,6 @@ #include #include -#include #include #include @@ -42,7 +41,7 @@ static char *conns[] = { "DATA ", "MESG ", "INDEX " }; /* This is slow, but it's simple. --RR */ static char amanda_buffer[65536]; -static DECLARE_LOCK(amanda_buffer_lock); +static DEFINE_SPINLOCK(amanda_buffer_lock); unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, @@ -76,7 +75,7 @@ static int help(struct sk_buff **pskb, return NF_ACCEPT; } - LOCK_BH(&amanda_buffer_lock); + spin_lock_bh(&amanda_buffer_lock); skb_copy_bits(*pskb, dataoff, amanda_buffer, (*pskb)->len - dataoff); data = amanda_buffer; data_limit = amanda_buffer + (*pskb)->len - dataoff; @@ -134,7 +133,7 @@ static int help(struct sk_buff **pskb, } out: - UNLOCK_BH(&amanda_buffer_lock); + spin_unlock_bh(&amanda_buffer_lock); return ret; } diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 09e8246..a7377a3 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -38,10 +38,10 @@ #include #include -/* This rwlock protects the main hash table, protocol/helper/expected +/* ip_conntrack_lock protects the main hash table, protocol/helper/expected registrations, conntrack timers*/ -#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) -#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock) +#define ASSERT_READ_LOCK(x) +#define ASSERT_WRITE_LOCK(x) #include #include @@ -57,7 +57,7 @@ #define DEBUGP(format, args...) #endif -DECLARE_RWLOCK(ip_conntrack_lock); +DEFINE_RWLOCK(ip_conntrack_lock); /* ip_conntrack_standalone needs this */ atomic_t ip_conntrack_count = ATOMIC_INIT(0); @@ -147,7 +147,7 @@ static void destroy_expect(struct ip_conntrack_expect *exp) static void unlink_expect(struct ip_conntrack_expect *exp) { - MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); + ASSERT_WRITE_LOCK(&ip_conntrack_lock); list_del(&exp->list); /* Logically in destroy_expect, but we hold the lock here. */ exp->master->expecting--; @@ -157,9 +157,9 @@ static void expectation_timed_out(unsigned long ul_expect) { struct ip_conntrack_expect *exp = (void *)ul_expect; - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); unlink_expect(exp); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); destroy_expect(exp); } @@ -209,7 +209,7 @@ clean_from_lists(struct ip_conntrack *ct) unsigned int ho, hr; DEBUGP("clean_from_lists(%p)\n", ct); - MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); + ASSERT_WRITE_LOCK(&ip_conntrack_lock); ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); @@ -240,7 +240,7 @@ destroy_conntrack(struct nf_conntrack *nfct) if (ip_conntrack_destroyed) ip_conntrack_destroyed(ct); - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); /* Expectations will have been removed in clean_from_lists, * except TFTP can create an expectation on the first packet, * before connection is in the list, so we need to clean here, @@ -254,7 +254,7 @@ destroy_conntrack(struct nf_conntrack *nfct) } CONNTRACK_STAT_INC(delete); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); if (ct->master) ip_conntrack_put(ct->master); @@ -268,12 +268,12 @@ static void death_by_timeout(unsigned long ul_conntrack) { struct ip_conntrack *ct = (void *)ul_conntrack; - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); /* Inside lock so preempt is disabled on module removal path. * Otherwise we can get spurious warnings. */ CONNTRACK_STAT_INC(delete_list); clean_from_lists(ct); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); ip_conntrack_put(ct); } @@ -282,7 +282,7 @@ conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i, const struct ip_conntrack_tuple *tuple, const struct ip_conntrack *ignored_conntrack) { - MUST_BE_READ_LOCKED(&ip_conntrack_lock); + ASSERT_READ_LOCK(&ip_conntrack_lock); return tuplehash_to_ctrack(i) != ignored_conntrack && ip_ct_tuple_equal(tuple, &i->tuple); } @@ -294,7 +294,7 @@ __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, struct ip_conntrack_tuple_hash *h; unsigned int hash = hash_conntrack(tuple); - MUST_BE_READ_LOCKED(&ip_conntrack_lock); + ASSERT_READ_LOCK(&ip_conntrack_lock); list_for_each_entry(h, &ip_conntrack_hash[hash], list) { if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) { CONNTRACK_STAT_INC(found); @@ -313,11 +313,11 @@ ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple, { struct ip_conntrack_tuple_hash *h; - READ_LOCK(&ip_conntrack_lock); + read_lock_bh(&ip_conntrack_lock); h = __ip_conntrack_find(tuple, ignored_conntrack); if (h) atomic_inc(&tuplehash_to_ctrack(h)->ct_general.use); - READ_UNLOCK(&ip_conntrack_lock); + read_unlock_bh(&ip_conntrack_lock); return h; } @@ -352,7 +352,7 @@ __ip_conntrack_confirm(struct sk_buff **pskb) IP_NF_ASSERT(!is_confirmed(ct)); DEBUGP("Confirming conntrack %p\n", ct); - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); /* See if there's one in the list already, including reverse: NAT could have grabbed it without realizing, since we're @@ -380,12 +380,12 @@ __ip_conntrack_confirm(struct sk_buff **pskb) atomic_inc(&ct->ct_general.use); set_bit(IPS_CONFIRMED_BIT, &ct->status); CONNTRACK_STAT_INC(insert); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); return NF_ACCEPT; } CONNTRACK_STAT_INC(insert_failed); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); return NF_DROP; } @@ -398,9 +398,9 @@ ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple, { struct ip_conntrack_tuple_hash *h; - READ_LOCK(&ip_conntrack_lock); + read_lock_bh(&ip_conntrack_lock); h = __ip_conntrack_find(tuple, ignored_conntrack); - READ_UNLOCK(&ip_conntrack_lock); + read_unlock_bh(&ip_conntrack_lock); return h != NULL; } @@ -419,13 +419,13 @@ static int early_drop(struct list_head *chain) struct ip_conntrack *ct = NULL; int dropped = 0; - READ_LOCK(&ip_conntrack_lock); + read_lock_bh(&ip_conntrack_lock); h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *); if (h) { ct = tuplehash_to_ctrack(h); atomic_inc(&ct->ct_general.use); } - READ_UNLOCK(&ip_conntrack_lock); + read_unlock_bh(&ip_conntrack_lock); if (!ct) return dropped; @@ -508,7 +508,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple, conntrack->timeout.data = (unsigned long)conntrack; conntrack->timeout.function = death_by_timeout; - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); exp = find_expectation(tuple); if (exp) { @@ -532,7 +532,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple, list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed); atomic_inc(&ip_conntrack_count); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); if (exp) { if (exp->expectfn) @@ -723,17 +723,17 @@ void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp) { struct ip_conntrack_expect *i; - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); /* choose the the oldest expectation to evict */ list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) { if (expect_matches(i, exp) && del_timer(&i->timeout)) { unlink_expect(i); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); destroy_expect(i); return; } } - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); } struct ip_conntrack_expect *ip_conntrack_expect_alloc(void) @@ -808,7 +808,7 @@ int ip_conntrack_expect_related(struct ip_conntrack_expect *expect) DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple); DEBUGP("mask: "); DUMP_TUPLE(&expect->mask); - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); list_for_each_entry(i, &ip_conntrack_expect_list, list) { if (expect_matches(i, expect)) { /* Refresh timer: if it's dying, ignore.. */ @@ -832,7 +832,7 @@ int ip_conntrack_expect_related(struct ip_conntrack_expect *expect) ip_conntrack_expect_insert(expect); ret = 0; out: - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); return ret; } @@ -841,7 +841,7 @@ out: void ip_conntrack_alter_reply(struct ip_conntrack *conntrack, const struct ip_conntrack_tuple *newreply) { - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); /* Should be unconfirmed, so not in hash table yet */ IP_NF_ASSERT(!is_confirmed(conntrack)); @@ -851,15 +851,15 @@ void ip_conntrack_alter_reply(struct ip_conntrack *conntrack, conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; if (!conntrack->master && conntrack->expecting == 0) conntrack->helper = ip_ct_find_helper(newreply); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); } int ip_conntrack_helper_register(struct ip_conntrack_helper *me) { BUG_ON(me->timeout == 0); - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); list_prepend(&helpers, me); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); return 0; } @@ -878,7 +878,7 @@ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) struct ip_conntrack_expect *exp, *tmp; /* Need write lock here, to delete helper. */ - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); LIST_DELETE(&helpers, me); /* Get rid of expectations */ @@ -893,7 +893,7 @@ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) for (i = 0; i < ip_conntrack_htable_size; i++) LIST_FIND_W(&ip_conntrack_hash[i], unhelp, struct ip_conntrack_tuple_hash *, me); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); /* Someone could be still looking at the helper in a bh. */ synchronize_net(); @@ -925,14 +925,14 @@ void ip_ct_refresh_acct(struct ip_conntrack *ct, ct->timeout.expires = extra_jiffies; ct_add_counters(ct, ctinfo, skb); } else { - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); /* Need del_timer for race avoidance (may already be dying). */ if (del_timer(&ct->timeout)) { ct->timeout.expires = jiffies + extra_jiffies; add_timer(&ct->timeout); } ct_add_counters(ct, ctinfo, skb); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); } } @@ -997,7 +997,7 @@ get_next_corpse(int (*iter)(struct ip_conntrack *i, void *data), { struct ip_conntrack_tuple_hash *h = NULL; - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); for (; *bucket < ip_conntrack_htable_size; (*bucket)++) { h = LIST_FIND_W(&ip_conntrack_hash[*bucket], do_iter, struct ip_conntrack_tuple_hash *, iter, data); @@ -1009,7 +1009,7 @@ get_next_corpse(int (*iter)(struct ip_conntrack *i, void *data), struct ip_conntrack_tuple_hash *, iter, data); if (h) atomic_inc(&tuplehash_to_ctrack(h)->ct_general.use); - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); return h; } @@ -1201,14 +1201,14 @@ int __init ip_conntrack_init(void) } /* Don't NEED lock here, but good form anyway. */ - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); for (i = 0; i < MAX_IP_CT_PROTO; i++) ip_ct_protos[i] = &ip_conntrack_generic_protocol; /* Sew in builtin protocols. */ ip_ct_protos[IPPROTO_TCP] = &ip_conntrack_protocol_tcp; ip_ct_protos[IPPROTO_UDP] = &ip_conntrack_protocol_udp; ip_ct_protos[IPPROTO_ICMP] = &ip_conntrack_protocol_icmp; - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); for (i = 0; i < ip_conntrack_htable_size; i++) INIT_LIST_HEAD(&ip_conntrack_hash[i]); diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index dd86503..fea6dd2 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c @@ -16,7 +16,6 @@ #include #include -#include #include #include #include @@ -28,7 +27,7 @@ MODULE_DESCRIPTION("ftp connection tracking helper"); /* This is slow, but it's simple. --RR */ static char ftp_buffer[65536]; -static DECLARE_LOCK(ip_ftp_lock); +static DEFINE_SPINLOCK(ip_ftp_lock); #define MAX_PORTS 8 static int ports[MAX_PORTS]; @@ -319,7 +318,7 @@ static int help(struct sk_buff **pskb, } datalen = (*pskb)->len - dataoff; - LOCK_BH(&ip_ftp_lock); + spin_lock_bh(&ip_ftp_lock); fb_ptr = skb_header_pointer(*pskb, dataoff, (*pskb)->len - dataoff, ftp_buffer); BUG_ON(fb_ptr == NULL); @@ -442,7 +441,7 @@ out_update_nl: if (ends_in_nl) update_nl_seq(seq, ct_ftp_info,dir); out: - UNLOCK_BH(&ip_ftp_lock); + spin_unlock_bh(&ip_ftp_lock); return ret; } diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index 33cc734..cd98772 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include @@ -41,7 +40,7 @@ static int max_dcc_channels = 8; static unsigned int dcc_timeout = 300; /* This is slow, but it's simple. --RR */ static char irc_buffer[65536]; -static DECLARE_LOCK(irc_buffer_lock); +static DEFINE_SPINLOCK(irc_buffer_lock); unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, @@ -141,7 +140,7 @@ static int help(struct sk_buff **pskb, if (dataoff >= (*pskb)->len) return NF_ACCEPT; - LOCK_BH(&irc_buffer_lock); + spin_lock_bh(&irc_buffer_lock); ib_ptr = skb_header_pointer(*pskb, dataoff, (*pskb)->len - dataoff, irc_buffer); BUG_ON(ib_ptr == NULL); @@ -237,7 +236,7 @@ static int help(struct sk_buff **pskb, } /* while data < ... */ out: - UNLOCK_BH(&irc_buffer_lock); + spin_unlock_bh(&irc_buffer_lock); return ret; } diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c index ff8c34a..31d7539 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c @@ -26,7 +26,6 @@ #include #include -#include #if 0 #define DEBUGP(format, ...) printk(format, ## __VA_ARGS__) @@ -35,7 +34,7 @@ #endif /* Protects conntrack->proto.sctp */ -static DECLARE_RWLOCK(sctp_lock); +static DEFINE_RWLOCK(sctp_lock); /* FIXME: Examine ipfilter's timeouts and conntrack transitions more closely. They're more complex. --RR @@ -199,9 +198,9 @@ static int sctp_print_conntrack(struct seq_file *s, DEBUGP(__FUNCTION__); DEBUGP("\n"); - READ_LOCK(&sctp_lock); + read_lock_bh(&sctp_lock); state = conntrack->proto.sctp.state; - READ_UNLOCK(&sctp_lock); + read_unlock_bh(&sctp_lock); return seq_printf(s, "%s ", sctp_conntrack_names[state]); } @@ -343,13 +342,13 @@ static int sctp_packet(struct ip_conntrack *conntrack, oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX; for_each_sctp_chunk (skb, sch, _sch, offset, count) { - WRITE_LOCK(&sctp_lock); + write_lock_bh(&sctp_lock); /* Special cases of Verification tag check (Sec 8.5.1) */ if (sch->type == SCTP_CID_INIT) { /* Sec 8.5.1 (A) */ if (sh->vtag != 0) { - WRITE_UNLOCK(&sctp_lock); + write_unlock_bh(&sctp_lock); return -1; } } else if (sch->type == SCTP_CID_ABORT) { @@ -357,7 +356,7 @@ static int sctp_packet(struct ip_conntrack *conntrack, if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)]) && !(sh->vtag == conntrack->proto.sctp.vtag [1 - CTINFO2DIR(ctinfo)])) { - WRITE_UNLOCK(&sctp_lock); + write_unlock_bh(&sctp_lock); return -1; } } else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) { @@ -366,13 +365,13 @@ static int sctp_packet(struct ip_conntrack *conntrack, && !(sh->vtag == conntrack->proto.sctp.vtag [1 - CTINFO2DIR(ctinfo)] && (sch->flags & 1))) { - WRITE_UNLOCK(&sctp_lock); + write_unlock_bh(&sctp_lock); return -1; } } else if (sch->type == SCTP_CID_COOKIE_ECHO) { /* Sec 8.5.1 (D) */ if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) { - WRITE_UNLOCK(&sctp_lock); + write_unlock_bh(&sctp_lock); return -1; } } @@ -384,7 +383,7 @@ static int sctp_packet(struct ip_conntrack *conntrack, if (newconntrack == SCTP_CONNTRACK_MAX) { DEBUGP("ip_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n", CTINFO2DIR(ctinfo), sch->type, oldsctpstate); - WRITE_UNLOCK(&sctp_lock); + write_unlock_bh(&sctp_lock); return -1; } @@ -396,7 +395,7 @@ static int sctp_packet(struct ip_conntrack *conntrack, ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t), sizeof(_inithdr), &_inithdr); if (ih == NULL) { - WRITE_UNLOCK(&sctp_lock); + write_unlock_bh(&sctp_lock); return -1; } DEBUGP("Setting vtag %x for dir %d\n", @@ -405,7 +404,7 @@ static int sctp_packet(struct ip_conntrack *conntrack, } conntrack->proto.sctp.state = newconntrack; - WRITE_UNLOCK(&sctp_lock); + write_unlock_bh(&sctp_lock); } ip_ct_refresh_acct(conntrack, ctinfo, skb, *sctp_timeouts[newconntrack]); diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index 721ddbf..809dfed 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -36,7 +36,6 @@ #include #include #include -#include #if 0 #define DEBUGP printk @@ -46,7 +45,7 @@ #endif /* Protects conntrack->proto.tcp */ -static DECLARE_RWLOCK(tcp_lock); +static DEFINE_RWLOCK(tcp_lock); /* "Be conservative in what you do, be liberal in what you accept from others." @@ -330,9 +329,9 @@ static int tcp_print_conntrack(struct seq_file *s, { enum tcp_conntrack state; - READ_LOCK(&tcp_lock); + read_lock_bh(&tcp_lock); state = conntrack->proto.tcp.state; - READ_UNLOCK(&tcp_lock); + read_unlock_bh(&tcp_lock); return seq_printf(s, "%s ", tcp_conntrack_names[state]); } @@ -738,14 +737,14 @@ void ip_conntrack_tcp_update(struct sk_buff *skb, end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, iph, tcph); - WRITE_LOCK(&tcp_lock); + write_lock_bh(&tcp_lock); /* * We have to worry for the ack in the reply packet only... */ if (after(end, conntrack->proto.tcp.seen[dir].td_end)) conntrack->proto.tcp.seen[dir].td_end = end; conntrack->proto.tcp.last_end = end; - WRITE_UNLOCK(&tcp_lock); + write_unlock_bh(&tcp_lock); DEBUGP("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, @@ -857,7 +856,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, sizeof(_tcph), &_tcph); BUG_ON(th == NULL); - WRITE_LOCK(&tcp_lock); + write_lock_bh(&tcp_lock); old_state = conntrack->proto.tcp.state; dir = CTINFO2DIR(ctinfo); index = get_conntrack_index(th); @@ -879,7 +878,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, * that the client cannot but retransmit its SYN and * thus initiate a clean new session. */ - WRITE_UNLOCK(&tcp_lock); + write_unlock_bh(&tcp_lock); if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, "ip_ct_tcp: killing out of sync session "); @@ -894,7 +893,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, conntrack->proto.tcp.last_end = segment_seq_plus_len(ntohl(th->seq), skb->len, iph, th); - WRITE_UNLOCK(&tcp_lock); + write_unlock_bh(&tcp_lock); if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, "ip_ct_tcp: invalid packet ignored "); @@ -904,7 +903,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, DEBUGP("ip_ct_tcp: Invalid dir=%i index=%u ostate=%u\n", dir, get_conntrack_index(th), old_state); - WRITE_UNLOCK(&tcp_lock); + write_unlock_bh(&tcp_lock); if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, "ip_ct_tcp: invalid state "); @@ -918,13 +917,13 @@ static int tcp_packet(struct ip_conntrack *conntrack, conntrack->proto.tcp.seen[dir].td_end)) { /* Attempt to reopen a closed connection. * Delete this connection and look up again. */ - WRITE_UNLOCK(&tcp_lock); + write_unlock_bh(&tcp_lock); if (del_timer(&conntrack->timeout)) conntrack->timeout.function((unsigned long) conntrack); return -NF_REPEAT; } else { - WRITE_UNLOCK(&tcp_lock); + write_unlock_bh(&tcp_lock); if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, "ip_ct_tcp: invalid SYN"); @@ -949,7 +948,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, if (!tcp_in_window(&conntrack->proto.tcp, dir, index, skb, iph, th)) { - WRITE_UNLOCK(&tcp_lock); + write_unlock_bh(&tcp_lock); return -NF_ACCEPT; } in_window: @@ -972,7 +971,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, timeout = conntrack->proto.tcp.retrans >= ip_ct_tcp_max_retrans && *tcp_timeouts[new_state] > ip_ct_tcp_timeout_max_retrans ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state]; - WRITE_UNLOCK(&tcp_lock); + write_unlock_bh(&tcp_lock); if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { /* If only reply is a RST, we can consider ourselves not to diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index bc59f7b..42dc951 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -28,8 +28,8 @@ #include #include -#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) -#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock) +#define ASSERT_READ_LOCK(x) +#define ASSERT_WRITE_LOCK(x) #include #include @@ -119,7 +119,7 @@ static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos) static void *ct_seq_start(struct seq_file *seq, loff_t *pos) { - READ_LOCK(&ip_conntrack_lock); + read_lock_bh(&ip_conntrack_lock); return ct_get_idx(seq, *pos); } @@ -131,7 +131,7 @@ static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) static void ct_seq_stop(struct seq_file *s, void *v) { - READ_UNLOCK(&ip_conntrack_lock); + read_unlock_bh(&ip_conntrack_lock); } static int ct_seq_show(struct seq_file *s, void *v) @@ -140,7 +140,7 @@ static int ct_seq_show(struct seq_file *s, void *v) const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash); struct ip_conntrack_protocol *proto; - MUST_BE_READ_LOCKED(&ip_conntrack_lock); + ASSERT_READ_LOCK(&ip_conntrack_lock); IP_NF_ASSERT(conntrack); /* we only want to print DIR_ORIGINAL */ @@ -239,7 +239,7 @@ static void *exp_seq_start(struct seq_file *s, loff_t *pos) /* strange seq_file api calls stop even if we fail, * thus we need to grab lock since stop unlocks */ - READ_LOCK(&ip_conntrack_lock); + read_lock_bh(&ip_conntrack_lock); if (list_empty(e)) return NULL; @@ -267,7 +267,7 @@ static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos) static void exp_seq_stop(struct seq_file *s, void *v) { - READ_UNLOCK(&ip_conntrack_lock); + read_unlock_bh(&ip_conntrack_lock); } static int exp_seq_show(struct seq_file *s, void *v) @@ -921,22 +921,22 @@ int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) { int ret = 0; - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) { ret = -EBUSY; goto out; } ip_ct_protos[proto->proto] = proto; out: - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); return ret; } void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) { - WRITE_LOCK(&ip_conntrack_lock); + write_lock_bh(&ip_conntrack_lock); ip_ct_protos[proto->proto] = &ip_conntrack_generic_protocol; - WRITE_UNLOCK(&ip_conntrack_lock); + write_unlock_bh(&ip_conntrack_lock); /* Somebody could be still looking at the proto in bh. */ synchronize_net(); diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 9fc6f93..739b6dd 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -22,8 +22,8 @@ #include #include -#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock) -#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock) +#define ASSERT_READ_LOCK(x) +#define ASSERT_WRITE_LOCK(x) #include #include @@ -41,7 +41,7 @@ #define DEBUGP(format, args...) #endif -DECLARE_RWLOCK(ip_nat_lock); +DEFINE_RWLOCK(ip_nat_lock); /* Calculated at init based on memory size */ static unsigned int ip_nat_htable_size; @@ -65,9 +65,9 @@ static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn) if (!(conn->status & IPS_NAT_DONE_MASK)) return; - WRITE_LOCK(&ip_nat_lock); + write_lock_bh(&ip_nat_lock); list_del(&conn->nat.info.bysource); - WRITE_UNLOCK(&ip_nat_lock); + write_unlock_bh(&ip_nat_lock); } /* We do checksum mangling, so if they were wrong before they're still @@ -142,7 +142,7 @@ find_appropriate_src(const struct ip_conntrack_tuple *tuple, unsigned int h = hash_by_src(tuple); struct ip_conntrack *ct; - READ_LOCK(&ip_nat_lock); + read_lock_bh(&ip_nat_lock); list_for_each_entry(ct, &bysource[h], nat.info.bysource) { if (same_src(ct, tuple)) { /* Copy source part from reply tuple. */ @@ -151,12 +151,12 @@ find_appropriate_src(const struct ip_conntrack_tuple *tuple, result->dst = tuple->dst; if (in_range(result, range)) { - READ_UNLOCK(&ip_nat_lock); + read_unlock_bh(&ip_nat_lock); return 1; } } } - READ_UNLOCK(&ip_nat_lock); + read_unlock_bh(&ip_nat_lock); return 0; } @@ -297,9 +297,9 @@ ip_nat_setup_info(struct ip_conntrack *conntrack, unsigned int srchash = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL] .tuple); - WRITE_LOCK(&ip_nat_lock); + write_lock_bh(&ip_nat_lock); list_add(&info->bysource, &bysource[srchash]); - WRITE_UNLOCK(&ip_nat_lock); + write_unlock_bh(&ip_nat_lock); } /* It's done. */ @@ -474,23 +474,23 @@ int ip_nat_protocol_register(struct ip_nat_protocol *proto) { int ret = 0; - WRITE_LOCK(&ip_nat_lock); + write_lock_bh(&ip_nat_lock); if (ip_nat_protos[proto->protonum] != &ip_nat_unknown_protocol) { ret = -EBUSY; goto out; } ip_nat_protos[proto->protonum] = proto; out: - WRITE_UNLOCK(&ip_nat_lock); + write_unlock_bh(&ip_nat_lock); return ret; } /* Noone stores the protocol anywhere; simply delete it. */ void ip_nat_protocol_unregister(struct ip_nat_protocol *proto) { - WRITE_LOCK(&ip_nat_lock); + write_lock_bh(&ip_nat_lock); ip_nat_protos[proto->protonum] = &ip_nat_unknown_protocol; - WRITE_UNLOCK(&ip_nat_lock); + write_unlock_bh(&ip_nat_lock); /* Someone could be still looking at the proto in a bh. */ synchronize_net(); @@ -509,13 +509,13 @@ int __init ip_nat_init(void) return -ENOMEM; /* Sew in builtin protocols. */ - WRITE_LOCK(&ip_nat_lock); + write_lock_bh(&ip_nat_lock); for (i = 0; i < MAX_IP_NAT_PROTO; i++) ip_nat_protos[i] = &ip_nat_unknown_protocol; ip_nat_protos[IPPROTO_TCP] = &ip_nat_protocol_tcp; ip_nat_protos[IPPROTO_UDP] = &ip_nat_protocol_udp; ip_nat_protos[IPPROTO_ICMP] = &ip_nat_protocol_icmp; - WRITE_UNLOCK(&ip_nat_lock); + write_unlock_bh(&ip_nat_lock); for (i = 0; i < ip_nat_htable_size; i++) { INIT_LIST_HEAD(&bysource[i]); diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index 1637b96..9cd51f1 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c @@ -28,8 +28,8 @@ #include #include -#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock) -#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock) +#define ASSERT_READ_LOCK(x) +#define ASSERT_WRITE_LOCK(x) #include #include @@ -47,7 +47,7 @@ #define DUMP_OFFSET(x) #endif -static DECLARE_LOCK(ip_nat_seqofs_lock); +static DEFINE_SPINLOCK(ip_nat_seqofs_lock); /* Setup TCP sequence correction given this change at this sequence */ static inline void @@ -70,7 +70,7 @@ adjust_tcp_sequence(u32 seq, DEBUGP("ip_nat_resize_packet: Seq_offset before: "); DUMP_OFFSET(this_way); - LOCK_BH(&ip_nat_seqofs_lock); + spin_lock_bh(&ip_nat_seqofs_lock); /* SYN adjust. If it's uninitialized, or this is after last * correction, record it: we don't handle more than one @@ -82,7 +82,7 @@ adjust_tcp_sequence(u32 seq, this_way->offset_before = this_way->offset_after; this_way->offset_after += sizediff; } - UNLOCK_BH(&ip_nat_seqofs_lock); + spin_unlock_bh(&ip_nat_seqofs_lock); DEBUGP("ip_nat_resize_packet: Seq_offset after: "); DUMP_OFFSET(this_way); diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c index 581f097..60d70fa 100644 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ b/net/ipv4/netfilter/ip_nat_rule.c @@ -19,8 +19,8 @@ #include #include -#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock) -#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock) +#define ASSERT_READ_LOCK(x) +#define ASSERT_WRITE_LOCK(x) #include #include diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 79f56f6..bc59d0d 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -31,8 +31,8 @@ #include #include -#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock) -#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock) +#define ASSERT_READ_LOCK(x) +#define ASSERT_WRITE_LOCK(x) #include #include @@ -373,7 +373,6 @@ static int init_or_cleanup(int init) cleanup_rule_init: ip_nat_rule_cleanup(); cleanup_nothing: - MUST_BE_READ_WRITE_UNLOCKED(&ip_nat_lock); return ret; } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 8a54f92..c88dfcd 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -67,7 +67,6 @@ static DECLARE_MUTEX(ipt_mutex); /* Must have mutex */ #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0) #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0) -#include #include #if 0 diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 0f12e3a..dc4362b 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -29,7 +29,6 @@ #include #include #include -#include #define CLUSTERIP_VERSION "0.6" @@ -41,6 +40,8 @@ #define DEBUGP #endif +#define ASSERT_READ_LOCK(x) + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("iptables target for CLUSTERIP"); @@ -67,7 +68,7 @@ static LIST_HEAD(clusterip_configs); /* clusterip_lock protects the clusterip_configs list _AND_ the configurable * data within all structurses (num_local_nodes, local_nodes[]) */ -static DECLARE_RWLOCK(clusterip_lock); +static DEFINE_RWLOCK(clusterip_lock); #ifdef CONFIG_PROC_FS static struct file_operations clusterip_proc_fops; @@ -82,9 +83,9 @@ clusterip_config_get(struct clusterip_config *c) { static inline void clusterip_config_put(struct clusterip_config *c) { if (atomic_dec_and_test(&c->refcount)) { - WRITE_LOCK(&clusterip_lock); + write_lock_bh(&clusterip_lock); list_del(&c->list); - WRITE_UNLOCK(&clusterip_lock); + write_unlock_bh(&clusterip_lock); dev_mc_delete(c->dev, c->clustermac, ETH_ALEN, 0); dev_put(c->dev); kfree(c); @@ -97,7 +98,7 @@ __clusterip_config_find(u_int32_t clusterip) { struct list_head *pos; - MUST_BE_READ_LOCKED(&clusterip_lock); + ASSERT_READ_LOCK(&clusterip_lock); list_for_each(pos, &clusterip_configs) { struct clusterip_config *c = list_entry(pos, struct clusterip_config, list); @@ -114,14 +115,14 @@ clusterip_config_find_get(u_int32_t clusterip) { struct clusterip_config *c; - READ_LOCK(&clusterip_lock); + read_lock_bh(&clusterip_lock); c = __clusterip_config_find(clusterip); if (!c) { - READ_UNLOCK(&clusterip_lock); + read_unlock_bh(&clusterip_lock); return NULL; } atomic_inc(&c->refcount); - READ_UNLOCK(&clusterip_lock); + read_unlock_bh(&clusterip_lock); return c; } @@ -160,9 +161,9 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, c->pde->data = c; #endif - WRITE_LOCK(&clusterip_lock); + write_lock_bh(&clusterip_lock); list_add(&c->list, &clusterip_configs); - WRITE_UNLOCK(&clusterip_lock); + write_unlock_bh(&clusterip_lock); return c; } @@ -172,25 +173,25 @@ clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum) { int i; - WRITE_LOCK(&clusterip_lock); + write_lock_bh(&clusterip_lock); if (c->num_local_nodes >= CLUSTERIP_MAX_NODES || nodenum > CLUSTERIP_MAX_NODES) { - WRITE_UNLOCK(&clusterip_lock); + write_unlock_bh(&clusterip_lock); return 1; } /* check if we alrady have this number in our array */ for (i = 0; i < c->num_local_nodes; i++) { if (c->local_nodes[i] == nodenum) { - WRITE_UNLOCK(&clusterip_lock); + write_unlock_bh(&clusterip_lock); return 1; } } c->local_nodes[c->num_local_nodes++] = nodenum; - WRITE_UNLOCK(&clusterip_lock); + write_unlock_bh(&clusterip_lock); return 0; } @@ -199,10 +200,10 @@ clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum) { int i; - WRITE_LOCK(&clusterip_lock); + write_lock_bh(&clusterip_lock); if (c->num_local_nodes <= 1 || nodenum > CLUSTERIP_MAX_NODES) { - WRITE_UNLOCK(&clusterip_lock); + write_unlock_bh(&clusterip_lock); return 1; } @@ -211,12 +212,12 @@ clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum) int size = sizeof(u_int16_t)*(c->num_local_nodes-(i+1)); memmove(&c->local_nodes[i], &c->local_nodes[i+1], size); c->num_local_nodes--; - WRITE_UNLOCK(&clusterip_lock); + write_unlock_bh(&clusterip_lock); return 0; } } - WRITE_UNLOCK(&clusterip_lock); + write_unlock_bh(&clusterip_lock); return 1; } @@ -286,21 +287,21 @@ clusterip_responsible(struct clusterip_config *config, u_int32_t hash) { int i; - READ_LOCK(&clusterip_lock); + read_lock_bh(&clusterip_lock); if (config->num_local_nodes == 0) { - READ_UNLOCK(&clusterip_lock); + read_unlock_bh(&clusterip_lock); return 0; } for (i = 0; i < config->num_local_nodes; i++) { if (config->local_nodes[i] == hash) { - READ_UNLOCK(&clusterip_lock); + read_unlock_bh(&clusterip_lock); return 1; } } - READ_UNLOCK(&clusterip_lock); + read_unlock_bh(&clusterip_lock); return 0; } @@ -578,7 +579,7 @@ static void *clusterip_seq_start(struct seq_file *s, loff_t *pos) struct clusterip_config *c = pde->data; unsigned int *nodeidx; - READ_LOCK(&clusterip_lock); + read_lock_bh(&clusterip_lock); if (*pos >= c->num_local_nodes) return NULL; @@ -608,7 +609,7 @@ static void clusterip_seq_stop(struct seq_file *s, void *v) { kfree(v); - READ_UNLOCK(&clusterip_lock); + read_unlock_bh(&clusterip_lock); } static int clusterip_seq_show(struct seq_file *s, void *v) diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 57e9f6c..91e7450 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -33,7 +33,7 @@ MODULE_DESCRIPTION("iptables MASQUERADE target module"); #endif /* Lock protects masq region inside conntrack */ -static DECLARE_RWLOCK(masq_lock); +static DEFINE_RWLOCK(masq_lock); /* FIXME: Multiple targets. --RR */ static int @@ -103,9 +103,9 @@ masquerade_target(struct sk_buff **pskb, return NF_DROP; } - WRITE_LOCK(&masq_lock); + write_lock_bh(&masq_lock); ct->nat.masq_index = out->ifindex; - WRITE_UNLOCK(&masq_lock); + write_unlock_bh(&masq_lock); /* Transfer from original range. */ newrange = ((struct ip_nat_range) @@ -122,9 +122,9 @@ device_cmp(struct ip_conntrack *i, void *ifindex) { int ret; - READ_LOCK(&masq_lock); + read_lock_bh(&masq_lock); ret = (i->nat.masq_index == (int)(long)ifindex); - READ_UNLOCK(&masq_lock); + read_unlock_bh(&masq_lock); return ret; } diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 6f2cefb..52a0076 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -56,7 +56,6 @@ #include #include #include -#include #include #include @@ -99,8 +98,8 @@ typedef struct { static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS]; /* array of buffers */ -static struct sock *nflognl; /* our socket */ -static DECLARE_LOCK(ulog_lock); /* spinlock */ +static struct sock *nflognl; /* our socket */ +static DEFINE_SPINLOCK(ulog_lock); /* spinlock */ /* send one ulog_buff_t to userspace */ static void ulog_send(unsigned int nlgroupnum) @@ -135,9 +134,9 @@ static void ulog_timer(unsigned long data) /* lock to protect against somebody modifying our structure * from ipt_ulog_target at the same time */ - LOCK_BH(&ulog_lock); + spin_lock_bh(&ulog_lock); ulog_send(data); - UNLOCK_BH(&ulog_lock); + spin_unlock_bh(&ulog_lock); } static struct sk_buff *ulog_alloc_skb(unsigned int size) @@ -193,7 +192,7 @@ static void ipt_ulog_packet(unsigned int hooknum, ub = &ulog_buffers[groupnum]; - LOCK_BH(&ulog_lock); + spin_lock_bh(&ulog_lock); if (!ub->skb) { if (!(ub->skb = ulog_alloc_skb(size))) @@ -278,7 +277,7 @@ static void ipt_ulog_packet(unsigned int hooknum, ulog_send(groupnum); } - UNLOCK_BH(&ulog_lock); + spin_unlock_bh(&ulog_lock); return; @@ -288,7 +287,7 @@ nlmsg_failure: alloc_failure: PRINTR("ipt_ULOG: Error building netlink message\n"); - UNLOCK_BH(&ulog_lock); + spin_unlock_bh(&ulog_lock); } static unsigned int ipt_ulog_target(struct sk_buff **pskb, diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c index f1937190..564b49b 100644 --- a/net/ipv4/netfilter/ipt_hashlimit.c +++ b/net/ipv4/netfilter/ipt_hashlimit.c @@ -37,7 +37,6 @@ #include #include -#include /* FIXME: this is just for IP_NF_ASSERRT */ #include @@ -92,7 +91,7 @@ struct ipt_hashlimit_htable { struct hlist_head hash[0]; /* hashtable itself */ }; -static DECLARE_LOCK(hashlimit_lock); /* protects htables list */ +static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */ static DECLARE_MUTEX(hlimit_mutex); /* additional checkentry protection */ static HLIST_HEAD(hashlimit_htables); static kmem_cache_t *hashlimit_cachep; @@ -233,9 +232,9 @@ static int htable_create(struct ipt_hashlimit_info *minfo) hinfo->timer.function = htable_gc; add_timer(&hinfo->timer); - LOCK_BH(&hashlimit_lock); + spin_lock_bh(&hashlimit_lock); hlist_add_head(&hinfo->node, &hashlimit_htables); - UNLOCK_BH(&hashlimit_lock); + spin_unlock_bh(&hashlimit_lock); return 0; } @@ -301,15 +300,15 @@ static struct ipt_hashlimit_htable *htable_find_get(char *name) struct ipt_hashlimit_htable *hinfo; struct hlist_node *pos; - LOCK_BH(&hashlimit_lock); + spin_lock_bh(&hashlimit_lock); hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) { if (!strcmp(name, hinfo->pde->name)) { atomic_inc(&hinfo->use); - UNLOCK_BH(&hashlimit_lock); + spin_unlock_bh(&hashlimit_lock); return hinfo; } } - UNLOCK_BH(&hashlimit_lock); + spin_unlock_bh(&hashlimit_lock); return NULL; } @@ -317,9 +316,9 @@ static struct ipt_hashlimit_htable *htable_find_get(char *name) static void htable_put(struct ipt_hashlimit_htable *hinfo) { if (atomic_dec_and_test(&hinfo->use)) { - LOCK_BH(&hashlimit_lock); + spin_lock_bh(&hashlimit_lock); hlist_del(&hinfo->node); - UNLOCK_BH(&hashlimit_lock); + spin_unlock_bh(&hashlimit_lock); htable_destroy(hinfo); } } diff --git a/net/ipv4/netfilter/ipt_helper.c b/net/ipv4/netfilter/ipt_helper.c index 33fdf36..3e7dd01 100644 --- a/net/ipv4/netfilter/ipt_helper.c +++ b/net/ipv4/netfilter/ipt_helper.c @@ -53,7 +53,7 @@ match(const struct sk_buff *skb, return ret; } - READ_LOCK(&ip_conntrack_lock); + read_lock_bh(&ip_conntrack_lock); if (!ct->master->helper) { DEBUGP("ipt_helper: master ct %p has no helper\n", exp->expectant); @@ -69,7 +69,7 @@ match(const struct sk_buff *skb, ret ^= !strncmp(ct->master->helper->name, info->name, strlen(ct->master->helper->name)); out_unlock: - READ_UNLOCK(&ip_conntrack_lock); + read_unlock_bh(&ip_conntrack_lock); return ret; } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index c735276..7303451 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -71,7 +71,6 @@ static DECLARE_MUTEX(ip6t_mutex); /* Must have mutex */ #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0) #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0) -#include #include #if 0 -- cgit v0.10.2 From 18b8afc771102b1b6af97962808291a7d27f52af Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 21 Jun 2005 14:01:57 -0700 Subject: [NETFILTER]: Kill nf_debug Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index 9e57500..3ebc36a 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -75,12 +75,6 @@ enum nf_ip_hook_priorities { #define SO_ORIGINAL_DST 80 #ifdef __KERNEL__ -#ifdef CONFIG_NETFILTER_DEBUG -void nf_debug_ip_local_deliver(struct sk_buff *skb); -void nf_debug_ip_loopback_xmit(struct sk_buff *newskb); -void nf_debug_ip_finish_output2(struct sk_buff *skb); -#endif /*CONFIG_NETFILTER_DEBUG*/ - extern int ip_route_me_harder(struct sk_buff **pskb); /* Call this before modifying an existing IP packet: ensures it is diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index cc04f5c..d7c839a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -193,7 +193,6 @@ struct skb_shared_info { * @nfcache: Cache info * @nfct: Associated connection, if any * @nfctinfo: Relationship of this skb to the connection - * @nf_debug: Netfilter debugging * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c * @private: Data which is private to the HIPPI implementation * @tc_index: Traffic control index @@ -264,9 +263,6 @@ struct sk_buff { __u32 nfcache; __u32 nfctinfo; struct nf_conntrack *nfct; -#ifdef CONFIG_NETFILTER_DEBUG - unsigned int nf_debug; -#endif #ifdef CONFIG_BRIDGE_NETFILTER struct nf_bridge_info *nf_bridge; #endif @@ -1219,15 +1215,6 @@ static inline void nf_reset(struct sk_buff *skb) { nf_conntrack_put(skb->nfct); skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -} -static inline void nf_reset_debug(struct sk_buff *skb) -{ -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif } #ifdef CONFIG_BRIDGE_NETFILTER diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index ef9f209..069253f 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -57,9 +57,6 @@ int br_forward_finish(struct sk_buff *skb) static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) { skb->dev = to->dev; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, br_forward_finish); } diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 8f5f2e7..9a45e62 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -23,11 +23,7 @@ const unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; static int br_pass_frame_up_finish(struct sk_buff *skb) { -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif netif_receive_skb(skb); - return 0; } diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index be03d3a..03ae4ed 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -102,10 +102,6 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug ^= (1 << NF_BR_PRE_ROUTING); -#endif - if (nf_bridge->mask & BRNF_PKT_TYPE) { skb->pkt_type = PACKET_OTHERHOST; nf_bridge->mask ^= BRNF_PKT_TYPE; @@ -182,10 +178,6 @@ static void __br_dnat_complain(void) * --Bart, 20021007 (updated) */ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) { -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug |= (1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_FORWARD); -#endif - if (skb->pkt_type == PACKET_OTHERHOST) { skb->pkt_type = PACKET_HOST; skb->nf_bridge->mask |= BRNF_PKT_TYPE; @@ -207,10 +199,6 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) struct iphdr *iph = skb->nh.iph; struct nf_bridge_info *nf_bridge = skb->nf_bridge; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug ^= (1 << NF_BR_PRE_ROUTING); -#endif - if (nf_bridge->mask & BRNF_PKT_TYPE) { skb->pkt_type = PACKET_OTHERHOST; nf_bridge->mask ^= BRNF_PKT_TYPE; @@ -382,9 +370,6 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb)) goto inhdr_error; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug ^= (1 << NF_IP6_PRE_ROUTING); -#endif if ((nf_bridge = nf_bridge_alloc(skb)) == NULL) return NF_DROP; setup_pre_routing(skb); @@ -468,9 +453,6 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, skb->ip_summed = CHECKSUM_NONE; } -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug ^= (1 << NF_IP_PRE_ROUTING); -#endif if ((nf_bridge = nf_bridge_alloc(skb)) == NULL) return NF_DROP; setup_pre_routing(skb); @@ -517,10 +499,6 @@ static int br_nf_forward_finish(struct sk_buff *skb) struct net_device *in; struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug ^= (1 << NF_BR_FORWARD); -#endif - if (skb->protocol != __constant_htons(ETH_P_ARP) && !IS_VLAN_ARP) { in = nf_bridge->physindev; if (nf_bridge->mask & BRNF_PKT_TYPE) { @@ -566,9 +544,6 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb, (*pskb)->nh.raw += VLAN_HLEN; } -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug ^= (1 << NF_BR_FORWARD); -#endif nf_bridge = skb->nf_bridge; if (skb->pkt_type == PACKET_OTHERHOST) { skb->pkt_type = PACKET_HOST; @@ -605,10 +580,6 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb, (*pskb)->nh.raw += VLAN_HLEN; } -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug ^= (1 << NF_BR_FORWARD); -#endif - if (skb->nh.arph->ar_pln != 4) { if (IS_VLAN_ARP) { skb_push(*pskb, VLAN_HLEN); @@ -627,9 +598,6 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb, /* PF_BRIDGE/LOCAL_OUT ***********************************************/ static int br_nf_local_out_finish(struct sk_buff *skb) { -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug &= ~(1 << NF_BR_LOCAL_OUT); -#endif if (skb->protocol == __constant_htons(ETH_P_8021Q)) { skb_push(skb, VLAN_HLEN); skb->nh.raw -= VLAN_HLEN; @@ -731,10 +699,6 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, realoutdev, br_nf_local_out_finish, NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD + 1); } else { -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug ^= (1 << NF_IP_LOCAL_OUT); -#endif - NF_HOOK_THRESH(pf, NF_IP_LOCAL_OUT, skb, realindev, realoutdev, br_nf_local_out_finish, NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT + 1); @@ -779,8 +743,6 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, printk(KERN_CRIT "br_netfilter: skb->dst == NULL."); goto print_error; } - - skb->nf_debug ^= (1 << NF_IP_POST_ROUTING); #endif /* We assume any code from br_dev_queue_push_xmit onwards doesn't care diff --git a/net/core/netfilter.c b/net/core/netfilter.c index 22a8f12..076c156 100644 --- a/net/core/netfilter.c +++ b/net/core/netfilter.c @@ -141,136 +141,6 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg) up(&nf_sockopt_mutex); } -#ifdef CONFIG_NETFILTER_DEBUG -#include -#include -#include - -static void debug_print_hooks_ip(unsigned int nf_debug) -{ - if (nf_debug & (1 << NF_IP_PRE_ROUTING)) { - printk("PRE_ROUTING "); - nf_debug ^= (1 << NF_IP_PRE_ROUTING); - } - if (nf_debug & (1 << NF_IP_LOCAL_IN)) { - printk("LOCAL_IN "); - nf_debug ^= (1 << NF_IP_LOCAL_IN); - } - if (nf_debug & (1 << NF_IP_FORWARD)) { - printk("FORWARD "); - nf_debug ^= (1 << NF_IP_FORWARD); - } - if (nf_debug & (1 << NF_IP_LOCAL_OUT)) { - printk("LOCAL_OUT "); - nf_debug ^= (1 << NF_IP_LOCAL_OUT); - } - if (nf_debug & (1 << NF_IP_POST_ROUTING)) { - printk("POST_ROUTING "); - nf_debug ^= (1 << NF_IP_POST_ROUTING); - } - if (nf_debug) - printk("Crap bits: 0x%04X", nf_debug); - printk("\n"); -} - -static void nf_dump_skb(int pf, struct sk_buff *skb) -{ - printk("skb: pf=%i %s dev=%s len=%u\n", - pf, - skb->sk ? "(owned)" : "(unowned)", - skb->dev ? skb->dev->name : "(no dev)", - skb->len); - switch (pf) { - case PF_INET: { - const struct iphdr *ip = skb->nh.iph; - __u32 *opt = (__u32 *) (ip + 1); - int opti; - __u16 src_port = 0, dst_port = 0; - - if (ip->protocol == IPPROTO_TCP - || ip->protocol == IPPROTO_UDP) { - struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl); - src_port = ntohs(tcp->source); - dst_port = ntohs(tcp->dest); - } - - printk("PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu" - " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu", - ip->protocol, NIPQUAD(ip->saddr), - src_port, NIPQUAD(ip->daddr), - dst_port, - ntohs(ip->tot_len), ip->tos, ntohs(ip->id), - ntohs(ip->frag_off), ip->ttl); - - for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++) - printk(" O=0x%8.8X", *opt++); - printk("\n"); - } - } -} - -void nf_debug_ip_local_deliver(struct sk_buff *skb) -{ - /* If it's a loopback packet, it must have come through - * NF_IP_LOCAL_OUT, NF_IP_RAW_INPUT, NF_IP_PRE_ROUTING and - * NF_IP_LOCAL_IN. Otherwise, must have gone through - * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING. */ - if (!skb->dev) { - printk("ip_local_deliver: skb->dev is NULL.\n"); - } else { - if (skb->nf_debug != ((1<nf_debug); - nf_dump_skb(PF_INET, skb); - } - } -} - -void nf_debug_ip_loopback_xmit(struct sk_buff *newskb) -{ - if (newskb->nf_debug != ((1 << NF_IP_LOCAL_OUT) - | (1 << NF_IP_POST_ROUTING))) { - printk("ip_dev_loopback_xmit: bad owned skb = %p: ", - newskb); - debug_print_hooks_ip(newskb->nf_debug); - nf_dump_skb(PF_INET, newskb); - } -} - -void nf_debug_ip_finish_output2(struct sk_buff *skb) -{ - /* If it's owned, it must have gone through the - * NF_IP_LOCAL_OUT and NF_IP_POST_ROUTING. - * Otherwise, must have gone through - * NF_IP_PRE_ROUTING, NF_IP_FORWARD and NF_IP_POST_ROUTING. - */ - if (skb->sk) { - if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) - | (1 << NF_IP_POST_ROUTING))) { - printk("ip_finish_output: bad owned skb = %p: ", skb); - debug_print_hooks_ip(skb->nf_debug); - nf_dump_skb(PF_INET, skb); - } - } else { - if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING) - | (1 << NF_IP_FORWARD) - | (1 << NF_IP_POST_ROUTING))) { - /* Fragments, entunnelled packets, TCP RSTs - generated by ipt_REJECT will have no - owners, but still may be local */ - if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) - | (1 << NF_IP_POST_ROUTING))){ - printk("ip_finish_output:" - " bad unowned skb = %p: ",skb); - debug_print_hooks_ip(skb->nf_debug); - nf_dump_skb(PF_INET, skb); - } - } - } -} -#endif /*CONFIG_NETFILTER_DEBUG*/ - /* Call get/setsockopt() */ static int nf_sockopt(struct sock *sk, int pf, int val, char __user *opt, int *len, int get) @@ -488,14 +358,6 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb, /* We may already have this, but read-locks nest anyway */ rcu_read_lock(); -#ifdef CONFIG_NETFILTER_DEBUG - if (unlikely((*pskb)->nf_debug & (1 << hook))) { - printk("nf_hook: hook %i already set.\n", hook); - nf_dump_skb(pf, *pskb); - } - (*pskb)->nf_debug |= (1 << hook); -#endif - elem = &nf_hooks[pf][hook]; next_hook: verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index f65b3de..6d68c03 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -365,9 +365,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) C(nfct); nf_conntrack_get(skb->nfct); C(nfctinfo); -#ifdef CONFIG_NETFILTER_DEBUG - C(nf_debug); -#endif #ifdef CONFIG_BRIDGE_NETFILTER C(nf_bridge); nf_bridge_get(skb->nf_bridge); @@ -432,9 +429,6 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->nfct = old->nfct; nf_conntrack_get(old->nfct); new->nfctinfo = old->nfctinfo; -#ifdef CONFIG_NETFILTER_DEBUG - new->nf_debug = old->nf_debug; -#endif #ifdef CONFIG_BRIDGE_NETFILTER new->nf_bridge = old->nf_bridge; nf_bridge_get(old->nf_bridge); diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 4e47a26..2b7485e 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -200,10 +200,6 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb) { int ihl = skb->nh.iph->ihl*4; -#ifdef CONFIG_NETFILTER_DEBUG - nf_debug_ip_local_deliver(skb); -#endif /*CONFIG_NETFILTER_DEBUG*/ - __skb_pull(skb, ihl); /* Free reference early: we don't need it any more, and it may diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 760dc82..ee07aec 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -107,10 +107,6 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb) newskb->pkt_type = PACKET_LOOPBACK; newskb->ip_summed = CHECKSUM_UNNECESSARY; BUG_TRAP(newskb->dst); - -#ifdef CONFIG_NETFILTER_DEBUG - nf_debug_ip_loopback_xmit(newskb); -#endif nf_reset(newskb); netif_rx(newskb); return 0; @@ -192,10 +188,6 @@ static inline int ip_finish_output2(struct sk_buff *skb) skb = skb2; } -#ifdef CONFIG_NETFILTER_DEBUG - nf_debug_ip_finish_output2(skb); -#endif /*CONFIG_NETFILTER_DEBUG*/ - nf_reset(skb); if (hh) { @@ -415,9 +407,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->nf_bridge = from->nf_bridge; nf_bridge_get(to->nf_bridge); #endif -#ifdef CONFIG_NETFILTER_DEBUG - to->nf_debug = from->nf_debug; -#endif #endif } diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c index de21da0..a8512a3 100644 --- a/net/ipv4/ipvs/ip_vs_xmit.c +++ b/net/ipv4/ipvs/ip_vs_xmit.c @@ -127,7 +127,6 @@ ip_vs_dst_reset(struct ip_vs_dest *dest) #define IP_VS_XMIT(skb, rt) \ do { \ - nf_reset_debug(skb); \ (skb)->nfcache |= NFC_IPVS_PROPERTY; \ (skb)->ip_summed = CHECKSUM_NONE; \ NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, (skb), NULL, \ diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index a7377a3..ffba0ad 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -940,10 +940,6 @@ void ip_ct_refresh_acct(struct ip_conntrack *ct, struct sk_buff * ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user) { -#ifdef CONFIG_NETFILTER_DEBUG - unsigned int olddebug = skb->nf_debug; -#endif - skb_orphan(skb); local_bh_disable(); @@ -953,12 +949,7 @@ ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user) if (skb) { ip_send_check(skb->nh.iph); skb->nfcache |= NFC_ALTERED; -#ifdef CONFIG_NETFILTER_DEBUG - /* Packet path as if nothing had happened. */ - skb->nf_debug = olddebug; -#endif } - return skb; } diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index 9cd51f1..158f34f 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c @@ -142,9 +142,6 @@ static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) /* Transfer socket to new skb. */ if ((*pskb)->sk) skb_set_owner_w(nskb, (*pskb)->sk); -#ifdef CONFIG_NETFILTER_DEBUG - nskb->nf_debug = (*pskb)->nf_debug; -#endif kfree_skb(*pskb); *pskb = nskb; return 1; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index b78a535..06e7cdae 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -484,9 +484,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->nf_bridge = from->nf_bridge; nf_bridge_get(to->nf_bridge); #endif -#ifdef CONFIG_NETFILTER_DEBUG - to->nf_debug = from->nf_debug; -#endif #endif } -- cgit v0.10.2 From e98231858bbfd2aca42f93d55133c2fca6df00f9 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 21 Jun 2005 14:02:15 -0700 Subject: [NETFILTER]: Restore netfilter assumptions in IPv6 multicast Netfilter assumes that skb->data == skb->nh.ipv6h Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index c0ca92e..562fcd1 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1301,15 +1301,6 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) return NULL; skb_reserve(skb, LL_RESERVED_SPACE(dev)); - if (dev->hard_header) { - unsigned char ha[MAX_ADDR_LEN]; - - ndisc_mc_map(&mld2_all_mcr, ha, dev, 1); - if (dev->hard_header(skb, dev, ETH_P_IPV6,ha,NULL,size) < 0) { - kfree_skb(skb); - return NULL; - } - } if (ipv6_get_lladdr(dev, &addr_buf)) { /* : @@ -1333,6 +1324,30 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) return skb; } +static inline int mld_dev_queue_xmit2(struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + + if (dev->hard_header) { + unsigned char ha[MAX_ADDR_LEN]; + int err; + + ndisc_mc_map(&skb->nh.ipv6h->daddr, ha, dev, 1); + err = dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len); + if (err < 0) { + kfree_skb(skb); + return err; + } + } + return dev_queue_xmit(skb); +} + +static inline int mld_dev_queue_xmit(struct sk_buff *skb) +{ + return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dev, + mld_dev_queue_xmit2); +} + static void mld_sendpack(struct sk_buff *skb) { struct ipv6hdr *pip6 = skb->nh.ipv6h; @@ -1350,7 +1365,7 @@ static void mld_sendpack(struct sk_buff *skb) pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, IPPROTO_ICMPV6, csum_partial(skb->h.raw, mldlen, 0)); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev, - dev_queue_xmit); + mld_dev_queue_xmit); if (!err) { ICMP6_INC_STATS(idev,ICMP6_MIB_OUTMSGS); IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS); @@ -1656,12 +1671,6 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) } skb_reserve(skb, LL_RESERVED_SPACE(dev)); - if (dev->hard_header) { - unsigned char ha[MAX_ADDR_LEN]; - ndisc_mc_map(snd_addr, ha, dev, 1); - if (dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len) < 0) - goto out; - } if (ipv6_get_lladdr(dev, &addr_buf)) { /* : @@ -1689,7 +1698,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) idev = in6_dev_get(skb->dev); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev, - dev_queue_xmit); + mld_dev_queue_xmit); if (!err) { if (type == ICMPV6_MGM_REDUCTION) ICMP6_INC_STATS(idev, ICMP6_MIB_OUTGROUPMEMBREDUCTIONS); @@ -1703,10 +1712,6 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) if (likely(idev != NULL)) in6_dev_put(idev); return; - -out: - IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); - kfree_skb(skb); } static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, -- cgit v0.10.2 From 1d3cdb41f52e299f70b66cbb569bff5216f3643a Mon Sep 17 00:00:00 2001 From: Phil Oester Date: Tue, 21 Jun 2005 14:02:42 -0700 Subject: [NETFILTER]: expectation timeouts are compulsory Since expectation timeouts were made compulsory [1], there is no need to check for them in ip_conntrack_expect_insert. [1] https://lists.netfilter.org/pipermail/netfilter-devel/2005-January/018143.html Signed-off-by: Phil Oester Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index ffba0ad..4b78ebe 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -760,15 +760,11 @@ static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp) exp->master->expecting++; list_add(&exp->list, &ip_conntrack_expect_list); - if (exp->master->helper->timeout) { - init_timer(&exp->timeout); - exp->timeout.data = (unsigned long)exp; - exp->timeout.function = expectation_timed_out; - exp->timeout.expires - = jiffies + exp->master->helper->timeout * HZ; - add_timer(&exp->timeout); - } else - exp->timeout.function = NULL; + init_timer(&exp->timeout); + exp->timeout.data = (unsigned long)exp; + exp->timeout.function = expectation_timed_out; + exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ; + add_timer(&exp->timeout); CONNTRACK_STAT_INC(expect_create); } -- cgit v0.10.2 From 97216c799a6496163be8c81c9ceed297d92956c5 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 21 Jun 2005 14:03:01 -0700 Subject: [NETFILTER]: Missing owner-field initialization in ip6table_raw I missed this one when fixing up iptable_raw. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 71407be..c2982ef 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -129,13 +129,15 @@ static struct nf_hook_ops ip6t_ops[] = { .hook = ip6t_hook, .pf = PF_INET6, .hooknum = NF_IP6_PRE_ROUTING, - .priority = NF_IP6_PRI_FIRST + .priority = NF_IP6_PRI_FIRST, + .owner = THIS_MODULE, }, { .hook = ip6t_hook, .pf = PF_INET6, .hooknum = NF_IP6_LOCAL_OUT, - .priority = NF_IP6_PRI_FIRST + .priority = NF_IP6_PRI_FIRST, + .owner = THIS_MODULE, }, }; -- cgit v0.10.2 From e3be8ba79294df5de96692411e122506b40c5aa4 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 21 Jun 2005 14:03:23 -0700 Subject: [NETFILTER]: Avoid unncessary checksum validation in UDP connection tracking Signed-off-by: Keir Fraser Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c index 5bc28a2..8c1eaba 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c @@ -120,6 +120,7 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, * and moreover root might send raw packets. * FIXME: Source route IP option packets --RR */ if (hooknum == NF_IP_PRE_ROUTING + && skb->ip_summed != CHECKSUM_UNNECESSARY && csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, skb->ip_summed == CHECKSUM_HW ? skb->csum : skb_checksum(skb, iph->ihl*4, udplen, 0))) { -- cgit v0.10.2 From 6150bacfec95c7042678667561664efcf10d4508 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 21 Jun 2005 14:03:46 -0700 Subject: [NETFILTER]: Check TCP checksum in ipt_REJECT Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 266d649..9156964 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -104,10 +104,12 @@ static inline struct rtable *route_reverse(struct sk_buff *skb, static void send_reset(struct sk_buff *oldskb, int hook) { struct sk_buff *nskb; + struct iphdr *iph = oldskb->nh.iph; struct tcphdr _otcph, *oth, *tcph; struct rtable *rt; u_int16_t tmp_port; u_int32_t tmp_addr; + unsigned int tcplen; int needs_ack; int hh_len; @@ -124,7 +126,16 @@ static void send_reset(struct sk_buff *oldskb, int hook) if (oth->rst) return; - /* FIXME: Check checksum --RR */ + /* Check checksum */ + tcplen = oldskb->len - iph->ihl * 4; + if (((hook != NF_IP_LOCAL_IN && oldskb->ip_summed != CHECKSUM_HW) || + (hook == NF_IP_LOCAL_IN && + oldskb->ip_summed != CHECKSUM_UNNECESSARY)) && + csum_tcpudp_magic(iph->saddr, iph->daddr, tcplen, IPPROTO_TCP, + oldskb->ip_summed == CHECKSUM_HW ? oldskb->csum : + skb_checksum(oldskb, iph->ihl * 4, tcplen, 0))) + return; + if ((rt = route_reverse(oldskb, oth, hook)) == NULL) return; -- cgit v0.10.2 From 2715bcf9efc34063e05009f188eb896c462ae925 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 21 Jun 2005 14:06:24 -0700 Subject: [NETFILTER]: Drop conntrack reference in ip_call_ra_chain()/ip_mr_input() Drop reference before handing the packets to raw_rcv() Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 2b7485e..af2ec88 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -184,6 +184,7 @@ int ip_call_ra_chain(struct sk_buff *skb) raw_rcv(last, skb2); } last = sk; + nf_reset(skb); } } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index e21c049..e4f809a 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1350,6 +1350,7 @@ int ip_mr_input(struct sk_buff *skb) */ read_lock(&mrt_lock); if (mroute_socket) { + nf_reset(skb); raw_rcv(mroute_socket, skb); read_unlock(&mrt_lock); return 0; -- cgit v0.10.2 From 047601bf7c803724bbab9a4fdbad9481cecc12e0 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 21 Jun 2005 14:07:13 -0700 Subject: [NETFILTER]: Fix ip6t_LOG sit tunnel logging Sit tunnel logging is currently broken: MAC=01:23:45:67:89:ab->01:23:45:47:89:ac TUNNEL=123.123. 0.123-> 12.123. 6.123 Apart from the broken IP address, MAC addresses are printed differently for sit tunnels than for everything else. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index bfc3d01..c44685e 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -366,8 +366,6 @@ ip6t_log_packet(unsigned int hooknum, const char *level_string, const char *prefix) { - struct ipv6hdr *ipv6h = skb->nh.ipv6h; - spin_lock_bh(&log_lock); printk(level_string); printk("%sIN=%s OUT=%s ", @@ -377,39 +375,25 @@ ip6t_log_packet(unsigned int hooknum, if (in && !out) { /* MAC logging for input chain only. */ printk("MAC="); - if (skb->dev && skb->dev->hard_header_len && skb->mac.raw != (void*)ipv6h) { - if (skb->dev->type != ARPHRD_SIT){ - int i; - unsigned char *p = skb->mac.raw; - for (i = 0; i < skb->dev->hard_header_len; i++,p++) - printk("%02x%c", *p, - i==skb->dev->hard_header_len - 1 - ? ' ':':'); - } else { - int i; - unsigned char *p = skb->mac.raw; - if ( p - (ETH_ALEN*2+2) > skb->head ){ - p -= (ETH_ALEN+2); - for (i = 0; i < (ETH_ALEN); i++,p++) - printk("%02x%s", *p, - i == ETH_ALEN-1 ? "->" : ":"); - p -= (ETH_ALEN*2); - for (i = 0; i < (ETH_ALEN); i++,p++) - printk("%02x%c", *p, - i == ETH_ALEN-1 ? ' ' : ':'); - } - - if ((skb->dev->addr_len == 4) && - skb->dev->hard_header_len > 20){ - printk("TUNNEL="); - p = skb->mac.raw + 12; - for (i = 0; i < 4; i++,p++) - printk("%3d%s", *p, - i == 3 ? "->" : "."); - for (i = 0; i < 4; i++,p++) - printk("%3d%c", *p, - i == 3 ? ' ' : '.'); - } + if (skb->dev && skb->dev->hard_header_len && + skb->mac.raw != skb->nh.raw) { + unsigned char *p = skb->mac.raw; + int i; + + if (skb->dev->type == ARPHRD_SIT && + (p -= ETH_HLEN) < skb->head) + p = NULL; + + if (p != NULL) + for (i = 0; i < skb->dev->hard_header_len; i++) + printk("%02x", p[i]); + printk(" "); + + if (skb->dev->type == ARPHRD_SIT) { + struct iphdr *iph = (struct iphdr *)skb->mac.raw; + printk("TUNNEL=%u.%u.%u.%u->%u.%u.%u.%u ", + NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); } } else printk(" "); -- cgit v0.10.2 From bd91c4bb134a3c5b04969f5ab960a3fd48778bcc Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Tue, 21 Jun 2005 14:16:00 -0700 Subject: [IA64] Refresh tiger_defconfig Signed-off-by: Tony Luck diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig index 9086b78..47f4534 100644 --- a/arch/ia64/configs/tiger_defconfig +++ b/arch/ia64/configs/tiger_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc3 -# Tue May 3 15:55:04 2005 +# Linux kernel version: 2.6.12-20050621 +# Tue Jun 21 14:03:24 2005 # # @@ -67,6 +67,7 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_TIME_INTERPOLATION=y CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y # CONFIG_IA64_GENERIC is not set CONFIG_IA64_DIG=y # CONFIG_IA64_HP_ZX1 is not set @@ -285,6 +286,7 @@ CONFIG_CHR_DEV_ST=m CONFIG_BLK_DEV_SR=m # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -313,11 +315,8 @@ CONFIG_SCSI_FC_ATTRS=y # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set # CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set @@ -366,8 +365,10 @@ CONFIG_DM_ZERO=m # Fusion MPT device support # CONFIG_FUSION=y -CONFIG_FUSION_MAX_SGE=40 -# CONFIG_FUSION_CTL is not set +CONFIG_FUSION_SPI=y +CONFIG_FUSION_FC=y +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_CTL=y # # IEEE 1394 (FireWire) support @@ -506,9 +507,11 @@ CONFIG_E1000=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SKGE is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=y +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) @@ -598,7 +601,6 @@ CONFIG_GAMEPORT=m # CONFIG_GAMEPORT_VORTEX is not set # CONFIG_GAMEPORT_FM801 is not set # CONFIG_GAMEPORT_CS461X is not set -CONFIG_SOUND_GAMEPORT=m # # Character devices @@ -611,7 +613,6 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_CYCLADES is not set # CONFIG_MOXA_SMARTIO is not set # CONFIG_ISI is not set -# CONFIG_SYNCLINK is not set # CONFIG_SYNCLINKMP is not set # CONFIG_N_HDLC is not set # CONFIG_SPECIALIX is not set -- cgit v0.10.2 From a35f1e03b868a3179fa12344ec0d46a44fbf7574 Mon Sep 17 00:00:00 2001 From: Greg Edwards Date: Tue, 21 Jun 2005 11:30:00 -0700 Subject: [IA64] enable SGI simulator for generic kernels Allow the SGI simulator (medusa) to work on generic kernels. There is no inherent dependency on an sn2-specific kernel. Boot tested on Altix, medusa and HP rx2600. Signed-off-by: Greg Edwards Signed-off-by: Tony Luck diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 3ad2c4a..992bcff 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -216,7 +216,7 @@ config IOSAPIC config IA64_SGI_SN_SIM bool "SGI Medusa Simulator Support" - depends on IA64_SGI_SN2 + depends on IA64_SGI_SN2 || IA64_GENERIC help If you are compiling a kernel that will run under SGI's IA-64 simulator (Medusa) then say Y, otherwise say N. -- cgit v0.10.2 From 52a0de2cd2d3da8f90d88e2eccb63d0cadd6ae26 Mon Sep 17 00:00:00 2001 From: Christophe Lucas Date: Mon, 20 Jun 2005 14:50:00 -0700 Subject: [IA64] printk needs KERN_INFO arch/ia64/kernel/smp.c printk() calls should include appropriate KERN_* constant. Signed-off-by: Christophe Lucas Signed-off-by: Domen Puncer Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index 953095e..b49d4dd 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -269,7 +269,7 @@ smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int int me = get_cpu(); /* prevent preemption and reschedule on another processor */ if (cpuid == me) { - printk("%s: trying to call self\n", __FUNCTION__); + printk(KERN_INFO "%s: trying to call self\n", __FUNCTION__); put_cpu(); return -EBUSY; } -- cgit v0.10.2 From 0393eed5c3220c9c3823a09a2d02329b8ff08b45 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Tue, 21 Jun 2005 14:40:31 -0700 Subject: [IA64] fix nested_dtlb_miss handler for hugetlb address The nested_dtlb_miss handler currently does not handle fault from hugetlb address correctly. It walks the page table assuming PAGE_SIZE. Thus when taking a fault triggered from hugetlb address, it would not calculate the pgd/pmd/pte address correctly and thus result an incorrect invocation of ia64_do_page_fault(). In there, kernel will signal SIGBUS and application dies (The faulting address is perfectly legal and we have a valid pte for the corresponding user hugetlb address as well). This patch fix the described kernel bug. Since nested_dtlb_miss is a rare event and a slow path anyway, I'm making the change without #ifdef CONFIG_HUGETLB_PAGE for code readability. Tony, please apply. Signed-off-by: Ken Chen Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index d9c05d5..2bc085a 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -405,17 +405,22 @@ ENTRY(nested_dtlb_miss) * r30: continuation address * r31: saved pr * - * Clobbered: b0, r18, r19, r21, psr.dt (cleared) + * Clobbered: b0, r18, r19, r21, r22, psr.dt (cleared) */ rsm psr.dt // switch to using physical data addressing mov r19=IA64_KR(PT_BASE) // get the page table base address shl r21=r16,3 // shift bit 60 into sign bit + mov r18=cr.itir ;; shr.u r17=r16,61 // get the region number into r17 + extr.u r18=r18,2,6 // get the faulting page size ;; cmp.eq p6,p7=5,r17 // is faulting address in region 5? - shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of faulting address + add r22=-PAGE_SHIFT,r18 // adjustment for hugetlb address + add r18=PGDIR_SHIFT-PAGE_SHIFT,r18 ;; + shr.u r22=r16,r22 + shr.u r18=r16,r18 (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place srlz.d @@ -428,7 +433,7 @@ ENTRY(nested_dtlb_miss) (p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 (p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) cmp.eq p7,p6=0,r21 // unused address bits all zeroes? - shr.u r18=r16,PMD_SHIFT // shift L2 index into position + shr.u r18=r22,PMD_SHIFT // shift L2 index into position ;; ld8 r17=[r17] // fetch the L1 entry (may be 0) ;; @@ -436,7 +441,7 @@ ENTRY(nested_dtlb_miss) dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry ;; (p7) ld8 r17=[r17] // fetch the L2 entry (may be 0) - shr.u r19=r16,PAGE_SHIFT // shift L3 index into position + shr.u r19=r22,PAGE_SHIFT // shift L3 index into position ;; (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry -- cgit v0.10.2 From 90f66914c89b0be63548d4387d1211280aa7bc8e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 21 Jun 2005 14:43:28 -0700 Subject: [IPV4]: Fix fib_trie.c's args to fib_dump_info(). Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index c0ece94..0671569 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1786,7 +1786,7 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi &xkey, plen, fa->fa_tos, - fa->fa_info) < 0) { + fa->fa_info, 0) < 0) { cb->args[3] = i; return -1; } -- cgit v0.10.2 From 7b404b3459db1326bbdc7085edb1f58b98da5826 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 13 Jun 2005 11:27:00 -0700 Subject: [IA64] remove "pci=routeirq" option Remove "pci=routeirq" option for ia64. This was a workaround after ACPI IRQ routing was changed from "all at boot for everything in _PRT" to "do it when the device is enabled" in case there were drivers that didn't use pci_enable_device(). Signed-off-by: Bjorn Helgaas Signed-off-by: Tony Luck diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 88641e5..e3fc4ed 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -33,8 +33,6 @@ #include -static int pci_routeirq; - /* * Low-level SAL-based PCI configuration access functions. Note that SAL * calls are already serialized (via sal_lock), so we don't need another @@ -139,24 +137,8 @@ static void acpi_map_iosapics(void) static int __init pci_acpi_init (void) { - struct pci_dev *dev = NULL; - - printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); - acpi_map_iosapics(); - if (pci_routeirq) { - /* - * PCI IRQ routing is set up by pci_enable_device(), but we - * also do it here in case there are still broken drivers that - * don't use pci_enable_device(). - */ - printk(KERN_INFO "PCI: Routing interrupts for all devices because \"pci=routeirq\" specified\n"); - for_each_pci_dev(dev) - acpi_pci_irq_enable(dev); - } else - printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\". If it helps, post a report\n"); - return 0; } @@ -500,8 +482,6 @@ pcibios_align_resource (void *data, struct resource *res, char * __init pcibios_setup (char *str) { - if (!strcmp(str, "routeirq")) - pci_routeirq = 1; return NULL; } -- cgit v0.10.2 From 8005aba69a6440a535a4cc2aed99ffca580847e0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 21 Jun 2005 15:39:22 -0700 Subject: [SPARC64]: Fix cmsg length checks in Solaris emulation layer. Signed-off-by: David S. Miller diff --git a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c index ec8e074..0674058 100644 --- a/arch/sparc64/solaris/socket.c +++ b/arch/sparc64/solaris/socket.c @@ -317,8 +317,10 @@ asmlinkage int solaris_sendmsg(int fd, struct sol_nmsghdr __user *user_msg, unsi unsigned long *kcmsg; compat_size_t cmlen; - if(kern_msg.msg_controllen > sizeof(ctl) && - kern_msg.msg_controllen <= 256) { + if (kern_msg.msg_controllen <= sizeof(compat_size_t)) + return -EINVAL; + + if(kern_msg.msg_controllen > sizeof(ctl)) { err = -ENOBUFS; ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL); if(!ctl_buf) -- cgit v0.10.2 From 2c6e5a839f92591a4bc6cac4a575d42151645af3 Mon Sep 17 00:00:00 2001 From: Greg KH Date: Tue, 21 Jun 2005 15:24:19 -0700 Subject: [PATCH] devfs: remove devfs from Kconfig preventing it from being built Here's a much smaller patch to simply disable devfs from the build. If this goes well, and there are no complaints for a few weeks, I'll resend my big "devfs-die-die-die" series of patches that rip the whole thing out of the kernel tree. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds diff --git a/fs/Kconfig b/fs/Kconfig index 6a4ad4b..178e274 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -741,56 +741,6 @@ config SYSFS Designers of embedded systems may wish to say N here to conserve space. -config DEVFS_FS - bool "/dev file system support (OBSOLETE)" - depends on EXPERIMENTAL - help - This is support for devfs, a virtual file system (like /proc) which - provides the file system interface to device drivers, normally found - in /dev. Devfs does not depend on major and minor number - allocations. Device drivers register entries in /dev which then - appear automatically, which means that the system administrator does - not have to create character and block special device files in the - /dev directory using the mknod command (or MAKEDEV script) anymore. - - This is work in progress. If you want to use this, you *must* read - the material in , especially - the file README there. - - Note that devfs no longer manages /dev/pts! If you are using UNIX98 - ptys, you will also need to mount the /dev/pts filesystem (devpts). - - Note that devfs has been obsoleted by udev, - . - It has been stripped down to a bare minimum and is only provided for - legacy installations that use its naming scheme which is - unfortunately different from the names normal Linux installations - use. - - If unsure, say N. - -config DEVFS_MOUNT - bool "Automatically mount at boot" - depends on DEVFS_FS - help - This option appears if you have CONFIG_DEVFS_FS enabled. Setting - this to 'Y' will make the kernel automatically mount devfs onto /dev - when the system is booted, before the init thread is started. - You can override this with the "devfs=nomount" boot option. - - If unsure, say N. - -config DEVFS_DEBUG - bool "Debug devfs" - depends on DEVFS_FS - help - If you say Y here, then the /dev file system code will generate - debugging messages. See the file - for more - details. - - If unsure, say N. - config DEVPTS_FS_XATTR bool "/dev/pts Extended Attributes" depends on UNIX98_PTYS -- cgit v0.10.2 From 4ea78729b8dbfc400fe165a57b90a394a7275a54 Mon Sep 17 00:00:00 2001 From: Matthew Chapman Date: Tue, 21 Jun 2005 16:19:20 -0700 Subject: [IA64] ptrace and restore_sigcontext() allow ar.rsc.pl==0 This patch fixes handling of accesses to ar.rsc via ptrace & restore_sigcontext [With Thanks to Chris Wright for noticing the restore_sigcontext path] Signed-off-by: Matthew Chapman Acked-by: David Mosberger Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 575a8f6..6d57aeb 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -945,6 +945,13 @@ access_uarea (struct task_struct *child, unsigned long addr, *data = (pt->cr_ipsr & IPSR_MASK); return 0; + case PT_AR_RSC: + if (write_access) + pt->ar_rsc = *data | (3 << 2); /* force PL3 */ + else + *data = pt->ar_rsc; + return 0; + case PT_AR_RNAT: urbs_end = ia64_get_user_rbs_end(child, pt, NULL); rnat_addr = (long) ia64_rse_rnat_addr((long *) @@ -996,9 +1003,6 @@ access_uarea (struct task_struct *child, unsigned long addr, case PT_AR_BSPSTORE: ptr = pt_reg_addr(pt, ar_bspstore); break; - case PT_AR_RSC: - ptr = pt_reg_addr(pt, ar_rsc); - break; case PT_AR_UNAT: ptr = pt_reg_addr(pt, ar_unat); break; @@ -1234,7 +1238,7 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) static long ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) { - unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val = 0; + unsigned long psr, rsc, ec, lc, rnat, bsp, cfm, nat_bits, val = 0; struct unw_frame_info info; struct switch_stack *sw; struct ia64_fpreg fpval; @@ -1267,7 +1271,7 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) /* app regs */ retval |= __get_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]); - retval |= __get_user(pt->ar_rsc, &ppr->ar[PT_AUR_RSC]); + retval |= __get_user(rsc, &ppr->ar[PT_AUR_RSC]); retval |= __get_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]); retval |= __get_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]); retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); @@ -1365,6 +1369,7 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) retval |= __get_user(nat_bits, &ppr->nat); retval |= access_uarea(child, PT_CR_IPSR, &psr, 1); + retval |= access_uarea(child, PT_AR_RSC, &rsc, 1); retval |= access_uarea(child, PT_AR_EC, &ec, 1); retval |= access_uarea(child, PT_AR_LC, &lc, 1); retval |= access_uarea(child, PT_AR_RNAT, &rnat, 1); diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 499b7e5..edd9f07 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -94,7 +94,7 @@ sys_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, long arg2, static long restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) { - unsigned long ip, flags, nat, um, cfm; + unsigned long ip, flags, nat, um, cfm, rsc; long err; /* Always make any pending restarted system calls return -EINTR */ @@ -106,7 +106,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) err |= __get_user(ip, &sc->sc_ip); /* instruction pointer */ err |= __get_user(cfm, &sc->sc_cfm); err |= __get_user(um, &sc->sc_um); /* user mask */ - err |= __get_user(scr->pt.ar_rsc, &sc->sc_ar_rsc); + err |= __get_user(rsc, &sc->sc_ar_rsc); err |= __get_user(scr->pt.ar_unat, &sc->sc_ar_unat); err |= __get_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr); err |= __get_user(scr->pt.ar_pfs, &sc->sc_ar_pfs); @@ -119,6 +119,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) err |= __copy_from_user(&scr->pt.r15, &sc->sc_gr[15], 8); /* r15 */ scr->pt.cr_ifs = cfm | (1UL << 63); + scr->pt.ar_rsc = rsc | (3 << 2); /* force PL3 */ /* establish new instruction pointer: */ scr->pt.cr_iip = ip & ~0x3UL; -- cgit v0.10.2 From 7049e6800f40046c384c522a990669024d5f5836 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 21 Jun 2005 16:20:28 -0700 Subject: [SPARC64]: Add prefetch support. The implementation is optimal for UltraSPARC-III and later. It will work, however suboptimally, on UltraSPARC-II and be treated as a NOP on UltraSPARC-I. It is not worth code patching this thing as the highest cost is the code space, and code patching cannot eliminate that. Signed-off-by: David S. Miller diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h index bc1445b..d0bee24 100644 --- a/include/asm-sparc64/processor.h +++ b/include/asm-sparc64/processor.h @@ -192,6 +192,40 @@ extern unsigned long get_wchan(struct task_struct *task); #define cpu_relax() barrier() +/* Prefetch support. This is tuned for UltraSPARC-III and later. + * UltraSPARC-I will treat these as nops, and UltraSPARC-II has + * a shallower prefetch queue than later chips. + */ +#define ARCH_HAS_PREFETCH +#define ARCH_HAS_PREFETCHW +#define ARCH_HAS_SPINLOCK_PREFETCH + +static inline void prefetch(const void *x) +{ + /* We do not use the read prefetch mnemonic because that + * prefetches into the prefetch-cache which only is accessible + * by floating point operations in UltraSPARC-III and later. + * By contrast, "#one_write" prefetches into the L2 cache + * in shared state. + */ + __asm__ __volatile__("prefetch [%0], #one_write" + : /* no outputs */ + : "r" (x)); +} + +static inline void prefetchw(const void *x) +{ + /* The most optimal prefetch to use for writes is + * "#n_writes". This brings the cacheline into the + * L2 cache in "owned" state. + */ + __asm__ __volatile__("prefetch [%0], #n_writes" + : /* no outputs */ + : "r" (x)); +} + +#define spin_lock_prefetch(x) prefetchw(x) + #endif /* !(__ASSEMBLY__) */ #endif /* !(__ASM_SPARC64_PROCESSOR_H) */ -- cgit v0.10.2 From e1a40fa907498030b6e432c0dbcb06d7a9f14ee3 Mon Sep 17 00:00:00 2001 From: Dean Roehrich Date: Wed, 22 Jun 2005 10:20:44 +1000 Subject: [XFS] Handle inode semaphores properly for dmapi queues SGI-PV: 931572 SGI-Modid: xfs-linux-melb:xfs-kern:189560a Signed-off-by: Dean Roehrich Signed-off-by: Nathan Scott diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 46b61a8..acab58c 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -280,10 +280,11 @@ xfs_read( if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && !(ioflags & IO_INVIS)) { vrwlock_t locktype = VRWLOCK_READ; + int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags); ret = -XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), *offset, size, - FILP_DELAY_FLAG(file), &locktype); + dmflags, &locktype); if (ret) { xfs_iunlock(ip, XFS_IOLOCK_SHARED); goto unlock_isem; @@ -843,11 +844,15 @@ retry: !(ioflags & IO_INVIS)) { xfs_rwunlock(bdp, locktype); + if (need_isem) + up(&inode->i_sem); error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp, DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL, 0, 0, 0); /* Delay flag intentionally unused */ if (error) - goto out_unlock_isem; + goto out_nounlocks; + if (need_isem) + down(&inode->i_sem); xfs_rwlock(bdp, locktype); pos = xip->i_d.di_size; ret = 0; @@ -962,6 +967,7 @@ retry: out_unlock_isem: if (need_isem) up(&inode->i_sem); + out_nounlocks: return -error; } diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h index 16cf9f7..55c17ad 100644 --- a/fs/xfs/xfs_dmapi.h +++ b/fs/xfs/xfs_dmapi.h @@ -166,27 +166,32 @@ typedef enum { #define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */ #define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */ #define DM_FLAGS_ISEM 0x004 /* thread holds i_sem */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21) -/* i_alloc_sem was added in 2.4.22-pre1 */ #define DM_FLAGS_IALLOCSEM_RD 0x010 /* thread holds i_alloc_sem rd */ #define DM_FLAGS_IALLOCSEM_WR 0x020 /* thread holds i_alloc_sem wr */ -#endif -#endif /* * Based on IO_ISDIRECT, decide which i_ flag is set. */ -#ifdef DM_FLAGS_IALLOCSEM_RD +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) +#define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \ + DM_FLAGS_ISEM : 0) +#define DM_SEM_FLAG_WR (DM_FLAGS_IALLOCSEM_WR | DM_FLAGS_ISEM) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22)) #define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \ DM_FLAGS_IALLOCSEM_RD : DM_FLAGS_ISEM) #define DM_SEM_FLAG_WR (DM_FLAGS_IALLOCSEM_WR | DM_FLAGS_ISEM) -#else +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,21) #define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \ 0 : DM_FLAGS_ISEM) #define DM_SEM_FLAG_WR (DM_FLAGS_ISEM) #endif + /* * Macros to turn caller specified delay/block flags into * dm_send_xxxx_event flag DM_FLAGS_NDELAY. @@ -209,8 +214,4 @@ void xfs_dm_exit(struct file_system_type *); #define XFS_DM_EXIT(fstype) #endif -#define HAVE_XFS_DM_MM -int xfs_dm_mm_get(struct vm_area_struct *vma); -void xfs_dm_mm_put(struct vm_area_struct *vma); - #endif /* __XFS_DMAPI_H__ */ -- cgit v0.10.2 From 9a558cb4ec43ccbe82e2cf899ced37f29ac017df Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:14:28 -0700 Subject: [PATCH] arm: irqs_disabled() type fix kernel/sched.c: In function `__might_sleep': kernel/sched.c:5461: warning: int format, long unsigned int arg (arg 3) We expect irqs_disabled() to return an int (poor man's bool). Acked-by: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index 8405eb6..39dd700 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h @@ -308,7 +308,7 @@ do { \ ({ \ unsigned long flags; \ local_save_flags(flags); \ - flags & PSR_I_BIT; \ + (int)(flags & PSR_I_BIT); \ }) #ifdef CONFIG_SMP -- cgit v0.10.2 From 7f20b6a4792c1b5033583c23b5594887dd3867b9 Mon Sep 17 00:00:00 2001 From: bobl Date: Tue, 21 Jun 2005 17:14:29 -0700 Subject: [PATCH] megaraid build fix Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 80b0c40..ec81532 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1975,7 +1975,7 @@ __megaraid_reset(Scsi_Cmnd *cmd) static int megaraid_reset(Scsi_Cmnd *cmd) { - adapter = (adapter_t *)cmd->device->host->hostdata; + adapter_t *adapter = (adapter_t *)cmd->device->host->hostdata; int rc; spin_lock_irq(&adapter->lock); -- cgit v0.10.2 From 3a845099b20e81fb678521f034bbdcd69208da4e Mon Sep 17 00:00:00 2001 From: Zaur Kambarov Date: Tue, 21 Jun 2005 17:14:30 -0700 Subject: [PATCH] coverity: ipmi: avoid overrun of ipmi_interfaces[] Fix overrun of static array "ipmi_interfaces" of size 4 at position 4 with index variable "if_num". Definitions involved: 297 #define MAX_IPMI_INTERFACES 4 298 static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES]; Signed-off-by: Zaur Kambarov Cc: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index d7fb452..0c81652 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -641,7 +641,7 @@ int ipmi_create_user(unsigned int if_num, return -ENOMEM; down_read(&interfaces_sem); - if ((if_num > MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL) + if ((if_num >= MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL) { rv = -EINVAL; goto out_unlock; -- cgit v0.10.2 From 589777eab7360894b7ca1c4ba9d252e03b51225b Mon Sep 17 00:00:00 2001 From: Zaur Kambarov Date: Tue, 21 Jun 2005 17:14:31 -0700 Subject: [PATCH] coverity: idr_get_new_above_int() overrun fix This patch fixes overrun of array pa: 92 struct idr_layer *pa[MAX_LEVEL]; in 98 l = idp->layers; 99 pa[l--] = NULL; by passing idp->layers, set in 202 idp->layers = layers; to function sub_alloc in 203 v = sub_alloc(idp, ptr, &id); Signed-off-by: Zaur Kambarov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/lib/idr.c b/lib/idr.c index 81fc430..c5be889 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -175,7 +175,7 @@ build_up: * Add a new layer to the top of the tree if the requested * id is larger than the currently allocated space. */ - while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) { + while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) { layers++; if (!p->count) continue; -- cgit v0.10.2 From 84929801e14d968caeb84795bfbb88f04283fbd9 Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Tue, 21 Jun 2005 17:14:32 -0700 Subject: [PATCH] x86_64: TASK_SIZE fixes for compatibility mode processes Appended patch will setup compatibility mode TASK_SIZE properly. This will fix atleast three known bugs that can be encountered while running compatibility mode apps. a) A malicious 32bit app can have an elf section at 0xffffe000. During exec of this app, we will have a memory leak as insert_vm_struct() is not checking for return value in syscall32_setup_pages() and thus not freeing the vma allocated for the vsyscall page. And instead of exec failing (as it has addresses > TASK_SIZE), we were allowing it to succeed previously. b) With a 32bit app, hugetlb_get_unmapped_area/arch_get_unmapped_area may return addresses beyond 32bits, ultimately causing corruption because of wrap-around and resulting in SEGFAULT, instead of returning ENOMEM. c) 32bit app doing this below mmap will now fail. mmap((void *)(0xFFFFE000UL), 0x10000UL, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANON, 0, 0); Signed-off-by: Zou Nan hai Signed-off-by: Suresh Siddha Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c index 99b5220..c8131f3 100644 --- a/arch/x86_64/ia32/ia32_binfmt.c +++ b/arch/x86_64/ia32/ia32_binfmt.c @@ -46,7 +46,7 @@ struct elf_phdr; #define IA32_EMULATOR 1 -#define ELF_ET_DYN_BASE (TASK_UNMAPPED_32 + 0x1000000) +#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000) #undef ELF_ARCH #define ELF_ARCH EM_386 @@ -307,9 +307,6 @@ MODULE_AUTHOR("Eric Youngdale, Andi Kleen"); #define elf_addr_t __u32 -#undef TASK_SIZE -#define TASK_SIZE 0xffffffff - static void elf32_init(struct pt_regs *); #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 761b6d3..dce8bab 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -656,7 +656,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) switch (code) { case ARCH_SET_GS: - if (addr >= TASK_SIZE) + if (addr >= TASK_SIZE_OF(task)) return -EPERM; cpu = get_cpu(); /* handle small bases via the GDT because that's faster to @@ -682,7 +682,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) case ARCH_SET_FS: /* Not strictly needed for fs, but do it for symmetry with gs */ - if (addr >= TASK_SIZE) + if (addr >= TASK_SIZE_OF(task)) return -EPERM; cpu = get_cpu(); /* handle small bases via the GDT because that's faster to diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index 525f6a1..bbf64b5 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -257,12 +257,12 @@ static int putreg(struct task_struct *child, value &= 0xffff; return 0; case offsetof(struct user_regs_struct,fs_base): - if (value >= TASK_SIZE) + if (value >= TASK_SIZE_OF(child)) return -EIO; child->thread.fs = value; return 0; case offsetof(struct user_regs_struct,gs_base): - if (value >= TASK_SIZE) + if (value >= TASK_SIZE_OF(child)) return -EIO; child->thread.gs = value; return 0; @@ -279,7 +279,7 @@ static int putreg(struct task_struct *child, break; case offsetof(struct user_regs_struct, rip): /* Check if the new RIP address is canonical */ - if (value >= TASK_SIZE) + if (value >= TASK_SIZE_OF(child)) return -EIO; break; } @@ -419,6 +419,8 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + { + int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7; ret = -EIO; if ((addr & 7) || addr > sizeof(struct user) - 7) @@ -430,22 +432,22 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; /* Disallows to set a breakpoint into the vsyscall */ case offsetof(struct user, u_debugreg[0]): - if (data >= TASK_SIZE-7) break; + if (data >= TASK_SIZE_OF(child) - dsize) break; child->thread.debugreg0 = data; ret = 0; break; case offsetof(struct user, u_debugreg[1]): - if (data >= TASK_SIZE-7) break; + if (data >= TASK_SIZE_OF(child) - dsize) break; child->thread.debugreg1 = data; ret = 0; break; case offsetof(struct user, u_debugreg[2]): - if (data >= TASK_SIZE-7) break; + if (data >= TASK_SIZE_OF(child) - dsize) break; child->thread.debugreg2 = data; ret = 0; break; case offsetof(struct user, u_debugreg[3]): - if (data >= TASK_SIZE-7) break; + if (data >= TASK_SIZE_OF(child) - dsize) break; child->thread.debugreg3 = data; ret = 0; break; @@ -469,6 +471,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; } break; + } case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c index dbebd5c..d9798dd 100644 --- a/arch/x86_64/kernel/sys_x86_64.c +++ b/arch/x86_64/kernel/sys_x86_64.c @@ -68,13 +68,7 @@ out: static void find_start_end(unsigned long flags, unsigned long *begin, unsigned long *end) { -#ifdef CONFIG_IA32_EMULATION - if (test_thread_flag(TIF_IA32)) { - *begin = TASK_UNMAPPED_32; - *end = IA32_PAGE_OFFSET; - } else -#endif - if (flags & MAP_32BIT) { + if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) { /* This is usually used needed to map code in small model, so it needs to be in the first 31bit. Limit it to that. This means we need to move the @@ -84,10 +78,10 @@ static void find_start_end(unsigned long flags, unsigned long *begin, of playground for now. -AK */ *begin = 0x40000000; *end = 0x80000000; - } else { - *begin = TASK_UNMAPPED_64; + } else { + *begin = TASK_UNMAPPED_BASE; *end = TASK_SIZE; - } + } } unsigned long diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 5d6b211..57d3ab1 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -350,7 +350,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) * (error_code & 4) == 0, and that the fault was not a * protection error (error_code & 1) == 0. */ - if (unlikely(address >= TASK_SIZE)) { + if (unlikely(address >= TASK_SIZE64)) { if (!(error_code & 5) && ((address >= VMALLOC_START && address < VMALLOC_END) || (address >= MODULES_VADDR && address < MODULES_END))) { diff --git a/include/asm-x86_64/a.out.h b/include/asm-x86_64/a.out.h index 5952914..7255cde 100644 --- a/include/asm-x86_64/a.out.h +++ b/include/asm-x86_64/a.out.h @@ -21,7 +21,7 @@ struct exec #ifdef __KERNEL__ #include -#define STACK_TOP (test_thread_flag(TIF_IA32) ? IA32_PAGE_OFFSET : TASK_SIZE) +#define STACK_TOP TASK_SIZE #endif #endif /* __A_OUT_GNU_H__ */ diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h index d641b19..8b55f13 100644 --- a/include/asm-x86_64/processor.h +++ b/include/asm-x86_64/processor.h @@ -160,16 +160,17 @@ static inline void clear_in_cr4 (unsigned long mask) /* * User space process size. 47bits minus one guard page. */ -#define TASK_SIZE (0x800000000000UL - 4096) +#define TASK_SIZE64 (0x800000000000UL - 4096) /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ #define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? 0xc0000000 : 0xFFFFe000) -#define TASK_UNMAPPED_32 PAGE_ALIGN(IA32_PAGE_OFFSET/3) -#define TASK_UNMAPPED_64 PAGE_ALIGN(TASK_SIZE/3) -#define TASK_UNMAPPED_BASE \ - (test_thread_flag(TIF_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64) + +#define TASK_SIZE (test_thread_flag(TIF_IA32) ? IA32_PAGE_OFFSET : TASK_SIZE64) +#define TASK_SIZE_OF(child) ((test_tsk_thread_flag(child, TIF_IA32)) ? IA32_PAGE_OFFSET : TASK_SIZE64) + +#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE/3) /* * Size of io_bitmap. -- cgit v0.10.2 From 39c715b71740c4a78ba4769fb54826929bac03cb Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 21 Jun 2005 17:14:34 -0700 Subject: [PATCH] smp_processor_id() cleanup This patch implements a number of smp_processor_id() cleanup ideas that Arjan van de Ven and I came up with. The previous __smp_processor_id/_smp_processor_id/smp_processor_id API spaghetti was hard to follow both on the implementational and on the usage side. Some of the complexity arose from picking wrong names, some of the complexity comes from the fact that not all architectures defined __smp_processor_id. In the new code, there are two externally visible symbols: - smp_processor_id(): debug variant. - raw_smp_processor_id(): nondebug variant. Replaces all existing uses of _smp_processor_id() and __smp_processor_id(). Defined by every SMP architecture in include/asm-*/smp.h. There is one new internal symbol, dependent on DEBUG_PREEMPT: - debug_smp_processor_id(): internal debug variant, mapped to smp_processor_id(). Also, i moved debug_smp_processor_id() from lib/kernel_lock.c into a new lib/smp_processor_id.c file. All related comments got updated and/or clarified. I have build/boot tested the following 8 .config combinations on x86: {SMP,UP} x {PREEMPT,!PREEMPT} x {DEBUG_PREEMPT,!DEBUG_PREEMPT} I have also build/boot tested x64 on UP/PREEMPT/DEBUG_PREEMPT. (Other architectures are untested, but should work just fine.) Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 00c6341..83c579e 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -306,7 +306,7 @@ void die(const char * str, struct pt_regs * regs, long err) }; static int die_counter; - if (die.lock_owner != _smp_processor_id()) { + if (die.lock_owner != raw_smp_processor_id()) { console_verbose(); spin_lock_irq(&die.lock); die.lock_owner = smp_processor_id(); diff --git a/arch/i386/lib/delay.c b/arch/i386/lib/delay.c index 080639f..eb0cdfe 100644 --- a/arch/i386/lib/delay.c +++ b/arch/i386/lib/delay.c @@ -34,7 +34,7 @@ inline void __const_udelay(unsigned long xloops) xloops *= 4; __asm__("mull %0" :"=d" (xloops), "=&a" (d0) - :"1" (xloops),"0" (cpu_data[_smp_processor_id()].loops_per_jiffy * (HZ/4))); + :"1" (xloops),"0" (cpu_data[raw_smp_processor_id()].loops_per_jiffy * (HZ/4))); __delay(++xloops); } diff --git a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c index 694163d..c450dc4 100644 --- a/arch/ppc/lib/locks.c +++ b/arch/ppc/lib/locks.c @@ -130,7 +130,7 @@ void _raw_read_lock(rwlock_t *rw) while (!read_can_lock(rw)) { if (--stuck == 0) { printk("_read_lock(%p) CPU#%d lock %d\n", - rw, _smp_processor_id(), rw->lock); + rw, raw_smp_processor_id(), rw->lock); stuck = INIT_STUCK; } } @@ -158,7 +158,7 @@ void _raw_write_lock(rwlock_t *rw) while (!write_can_lock(rw)) { if (--stuck == 0) { printk("write_lock(%p) CPU#%d lock %d)\n", - rw, _smp_processor_id(), rw->lock); + rw, raw_smp_processor_id(), rw->lock); stuck = INIT_STUCK; } } diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c index f24ce2b..ff8a7db 100644 --- a/arch/ppc64/kernel/idle.c +++ b/arch/ppc64/kernel/idle.c @@ -292,7 +292,7 @@ static int native_idle(void) if (need_resched()) schedule(); - if (cpu_is_offline(_smp_processor_id()) && + if (cpu_is_offline(raw_smp_processor_id()) && system_state == SYSTEM_RUNNING) cpu_die(); } diff --git a/arch/sh/lib/delay.c b/arch/sh/lib/delay.c index 50b3603..3517146 100644 --- a/arch/sh/lib/delay.c +++ b/arch/sh/lib/delay.c @@ -24,7 +24,7 @@ inline void __const_udelay(unsigned long xloops) __asm__("dmulu.l %0, %2\n\t" "sts mach, %0" : "=r" (xloops) - : "0" (xloops), "r" (cpu_data[_smp_processor_id()].loops_per_jiffy) + : "0" (xloops), "r" (cpu_data[raw_smp_processor_id()].loops_per_jiffy) : "macl", "mach"); __delay(xloops * HZ); } diff --git a/arch/sparc64/lib/delay.c b/arch/sparc64/lib/delay.c index f6b4c78..e880872 100644 --- a/arch/sparc64/lib/delay.c +++ b/arch/sparc64/lib/delay.c @@ -31,7 +31,7 @@ void __const_udelay(unsigned long n) { n *= 4; - n *= (cpu_data(_smp_processor_id()).udelay_val * (HZ/4)); + n *= (cpu_data(raw_smp_processor_id()).udelay_val * (HZ/4)); n >>= 32; __delay(n + 1); diff --git a/arch/x86_64/lib/delay.c b/arch/x86_64/lib/delay.c index 6e2d664..aed61a6 100644 --- a/arch/x86_64/lib/delay.c +++ b/arch/x86_64/lib/delay.c @@ -34,7 +34,7 @@ void __delay(unsigned long loops) inline void __const_udelay(unsigned long xloops) { - __delay(((xloops * cpu_data[_smp_processor_id()].loops_per_jiffy) >> 32) * HZ); + __delay(((xloops * cpu_data[raw_smp_processor_id()].loops_per_jiffy) >> 32) * HZ); } void __udelay(unsigned long usecs) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ff64d33..c9d671c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -171,7 +171,7 @@ static void acpi_processor_idle (void) int sleep_ticks = 0; u32 t1, t2 = 0; - pr = processors[_smp_processor_id()]; + pr = processors[raw_smp_processor_id()]; if (!pr) return; diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 9b8ff39..e152d0f 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -134,7 +134,7 @@ static int gameport_measure_speed(struct gameport *gameport) } gameport_close(gameport); - return (cpu_data[_smp_processor_id()].loops_per_jiffy * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx); + return (cpu_data[raw_smp_processor_id()].loops_per_jiffy * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx); #else diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 55720dc..745a141 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -62,7 +62,7 @@ static int task_exit_notify(struct notifier_block * self, unsigned long val, voi /* To avoid latency problems, we only process the current CPU, * hoping that most samples for the task are on this CPU */ - sync_buffer(_smp_processor_id()); + sync_buffer(raw_smp_processor_id()); return 0; } @@ -86,7 +86,7 @@ static int munmap_notify(struct notifier_block * self, unsigned long val, void * /* To avoid latency problems, we only process the current CPU, * hoping that most samples for the task are on this CPU */ - sync_buffer(_smp_processor_id()); + sync_buffer(raw_smp_processor_id()); return 0; } diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index 71bb410..7d7c878 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h @@ -145,10 +145,10 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh) #define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val #define xfs_rotorstep xfs_params.rotorstep.val -#ifndef __smp_processor_id -#define __smp_processor_id() smp_processor_id() +#ifndef raw_smp_processor_id +#define raw_smp_processor_id() smp_processor_id() #endif -#define current_cpu() __smp_processor_id() +#define current_cpu() raw_smp_processor_id() #define current_pid() (current->pid) #define current_fsuid(cred) (current->fsuid) #define current_fsgid(cred) (current->fsgid) diff --git a/include/asm-alpha/smp.h b/include/asm-alpha/smp.h index cbc173a..9950706 100644 --- a/include/asm-alpha/smp.h +++ b/include/asm-alpha/smp.h @@ -43,7 +43,7 @@ extern struct cpuinfo_alpha cpu_data[NR_CPUS]; #define PROC_CHANGE_PENALTY 20 #define hard_smp_processor_id() __hard_smp_processor_id() -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) extern cpumask_t cpu_present_mask; extern cpumask_t cpu_online_map; diff --git a/include/asm-arm/smp.h b/include/asm-arm/smp.h index bd44f89..6c6c60a 100644 --- a/include/asm-arm/smp.h +++ b/include/asm-arm/smp.h @@ -21,7 +21,7 @@ # error " included in non-SMP build" #endif -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) extern cpumask_t cpu_present_mask; #define cpu_possible_map cpu_present_mask diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h index e03a206..55ef31f 100644 --- a/include/asm-i386/smp.h +++ b/include/asm-i386/smp.h @@ -51,7 +51,7 @@ extern u8 x86_cpu_to_apicid[]; * from the initial startup. We map APIC_BASE very early in page_setup(), * so this is correct in the x86 case. */ -#define __smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) extern cpumask_t cpu_callout_map; extern cpumask_t cpu_callin_map; diff --git a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h index 3ba1a06..a391435 100644 --- a/include/asm-ia64/smp.h +++ b/include/asm-ia64/smp.h @@ -46,7 +46,7 @@ ia64_get_lid (void) #define SMP_IRQ_REDIRECTION (1 << 0) #define SMP_IPI_REDIRECTION (1 << 1) -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) extern struct smp_boot_data { int cpu_count; diff --git a/include/asm-m32r/smp.h b/include/asm-m32r/smp.h index 8cd4d0d..b9a20cd 100644 --- a/include/asm-m32r/smp.h +++ b/include/asm-m32r/smp.h @@ -66,7 +66,7 @@ extern volatile int cpu_2_physid[NR_CPUS]; #define physid_to_cpu(physid) physid_2_cpu[physid] #define cpu_to_physid(cpu_id) cpu_2_physid[cpu_id] -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) extern cpumask_t cpu_callout_map; #define cpu_possible_map cpu_callout_map diff --git a/include/asm-mips/smp.h b/include/asm-mips/smp.h index 8ba370e..5618f1e 100644 --- a/include/asm-mips/smp.h +++ b/include/asm-mips/smp.h @@ -21,7 +21,7 @@ #include #include -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) /* Map from cpu id to sequential logical cpu number. This will only not be idempotent when cpus failed to come on-line. */ diff --git a/include/asm-parisc/smp.h b/include/asm-parisc/smp.h index fde77ac..9413f67 100644 --- a/include/asm-parisc/smp.h +++ b/include/asm-parisc/smp.h @@ -51,7 +51,7 @@ extern void smp_send_reschedule(int cpu); extern unsigned long cpu_present_mask; -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) #endif /* CONFIG_SMP */ diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h index ebfb614..17530c2 100644 --- a/include/asm-ppc/smp.h +++ b/include/asm-ppc/smp.h @@ -44,7 +44,7 @@ extern void smp_message_recv(int, struct pt_regs *); #define NO_PROC_ID 0xFF /* No processor magic marker */ #define PROC_CHANGE_PENALTY 20 -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) extern int __cpu_up(unsigned int cpu); diff --git a/include/asm-ppc64/smp.h b/include/asm-ppc64/smp.h index c8646fa..8115ecb 100644 --- a/include/asm-ppc64/smp.h +++ b/include/asm-ppc64/smp.h @@ -45,7 +45,7 @@ void generic_cpu_die(unsigned int cpu); void generic_mach_cpu_die(void); #endif -#define __smp_processor_id() (get_paca()->paca_index) +#define raw_smp_processor_id() (get_paca()->paca_index) #define hard_smp_processor_id() (get_paca()->hw_cpu_id) extern cpumask_t cpu_sibling_map[NR_CPUS]; diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h index 9473786..dd50e57 100644 --- a/include/asm-s390/smp.h +++ b/include/asm-s390/smp.h @@ -47,7 +47,7 @@ extern int smp_call_function_on(void (*func) (void *info), void *info, #define PROC_CHANGE_PENALTY 20 /* Schedule penalty */ -#define smp_processor_id() (S390_lowcore.cpu_data.cpu_nr) +#define raw_smp_processor_id() (S390_lowcore.cpu_data.cpu_nr) extern int smp_get_cpu(cpumask_t cpu_map); extern void smp_put_cpu(int cpu); diff --git a/include/asm-sh/smp.h b/include/asm-sh/smp.h index 38b5446..f19a8b3 100644 --- a/include/asm-sh/smp.h +++ b/include/asm-sh/smp.h @@ -25,7 +25,7 @@ extern cpumask_t cpu_possible_map; #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) /* I've no idea what the real meaning of this is */ #define PROC_CHANGE_PENALTY 20 diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h index f986c0d..4f96d83 100644 --- a/include/asm-sparc/smp.h +++ b/include/asm-sparc/smp.h @@ -148,7 +148,7 @@ extern __inline__ int hard_smp_processor_id(void) } #endif -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) #define prof_multiplier(__cpu) cpu_data(__cpu).multiplier #define prof_counter(__cpu) cpu_data(__cpu).counter diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index 5e3e06d..110a2de 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h @@ -64,7 +64,7 @@ static __inline__ int hard_smp_processor_id(void) } } -#define smp_processor_id() (current_thread_info()->cpu) +#define raw_smp_processor_id() (current_thread_info()->cpu) #endif /* !(__ASSEMBLY__) */ diff --git a/include/asm-um/smp.h b/include/asm-um/smp.h index 4412d5d..d879eba 100644 --- a/include/asm-um/smp.h +++ b/include/asm-um/smp.h @@ -8,7 +8,8 @@ #include "asm/current.h" #include "linux/cpumask.h" -#define smp_processor_id() (current_thread->cpu) +#define raw_smp_processor_id() (current_thread->cpu) + #define cpu_logical_map(n) (n) #define cpu_number_map(n) (n) #define PROC_CHANGE_PENALTY 15 /* Pick a number, any number */ diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h index 96844fe..a7425aa 100644 --- a/include/asm-x86_64/smp.h +++ b/include/asm-x86_64/smp.h @@ -68,7 +68,7 @@ static inline int num_booting_cpus(void) return cpus_weight(cpu_callout_map); } -#define __smp_processor_id() read_pda(cpunumber) +#define raw_smp_processor_id() read_pda(cpunumber) extern __inline int hard_smp_processor_id(void) { diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index e530c6c..beacd93 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -381,7 +381,7 @@ int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *, int, struct file *, #include /* Returns the number of the current Node. */ -#define numa_node_id() (cpu_to_node(_smp_processor_id())) +#define numa_node_id() (cpu_to_node(raw_smp_processor_id())) #ifndef CONFIG_DISCONTIGMEM diff --git a/include/linux/smp.h b/include/linux/smp.h index dcf1db3..9dfa3ee 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -92,10 +92,7 @@ void smp_prepare_boot_cpu(void); /* * These macros fold the SMP functionality into a single CPU system */ - -#if !defined(__smp_processor_id) || !defined(CONFIG_PREEMPT) -# define smp_processor_id() 0 -#endif +#define raw_smp_processor_id() 0 #define hard_smp_processor_id() 0 #define smp_call_function(func,info,retry,wait) ({ 0; }) #define on_each_cpu(func,info,retry,wait) ({ func(info); 0; }) @@ -106,30 +103,25 @@ static inline void smp_send_reschedule(int cpu) { } #endif /* !SMP */ /* - * DEBUG_PREEMPT support: check whether smp_processor_id() is being - * used in a preemption-safe way. + * smp_processor_id(): get the current CPU ID. * - * An architecture has to enable this debugging code explicitly. - * It can do so by renaming the smp_processor_id() macro to - * __smp_processor_id(). This should only be done after some minimal - * testing, because usually there are a number of false positives - * that an architecture will trigger. + * if DEBUG_PREEMPT is enabled the we check whether it is + * used in a preemption-safe way. (smp_processor_id() is safe + * if it's used in a preemption-off critical section, or in + * a thread that is bound to the current CPU.) * - * To fix a false positive (i.e. smp_processor_id() use that the - * debugging code reports but which use for some reason is legal), - * change the smp_processor_id() reference to _smp_processor_id(), - * which is the nondebug variant. NOTE: don't use this to hack around - * real bugs. + * NOTE: raw_smp_processor_id() is for internal use only + * (smp_processor_id() is the preferred variant), but in rare + * instances it might also be used to turn off false positives + * (i.e. smp_processor_id() use that the debugging code reports but + * which use for some reason is legal). Don't use this to hack around + * the warning message, as your code might not work under PREEMPT. */ -#ifdef __smp_processor_id -# if defined(CONFIG_PREEMPT) && defined(CONFIG_DEBUG_PREEMPT) - extern unsigned int smp_processor_id(void); -# else -# define smp_processor_id() __smp_processor_id() -# endif -# define _smp_processor_id() __smp_processor_id() +#ifdef CONFIG_DEBUG_PREEMPT + extern unsigned int debug_smp_processor_id(void); +# define smp_processor_id() debug_smp_processor_id() #else -# define _smp_processor_id() smp_processor_id() +# define smp_processor_id() raw_smp_processor_id() #endif #define get_cpu() ({ preempt_disable(); smp_processor_id(); }) diff --git a/include/net/route.h b/include/net/route.h index d34ca8f..c3cd069 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -107,7 +107,7 @@ struct rt_cache_stat extern struct rt_cache_stat *rt_cache_stat; #define RT_CACHE_STAT_INC(field) \ - (per_cpu_ptr(rt_cache_stat, _smp_processor_id())->field++) + (per_cpu_ptr(rt_cache_stat, raw_smp_processor_id())->field++) extern struct ip_rt_acct *ip_rt_acct; diff --git a/include/net/snmp.h b/include/net/snmp.h index a15ab25..a36bed8 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -128,18 +128,18 @@ struct linux_mib { #define SNMP_STAT_USRPTR(name) (name[1]) #define SNMP_INC_STATS_BH(mib, field) \ - (per_cpu_ptr(mib[0], _smp_processor_id())->mibs[field]++) + (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field]++) #define SNMP_INC_STATS_OFFSET_BH(mib, field, offset) \ - (per_cpu_ptr(mib[0], _smp_processor_id())->mibs[field + (offset)]++) + (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field + (offset)]++) #define SNMP_INC_STATS_USER(mib, field) \ - (per_cpu_ptr(mib[1], _smp_processor_id())->mibs[field]++) + (per_cpu_ptr(mib[1], raw_smp_processor_id())->mibs[field]++) #define SNMP_INC_STATS(mib, field) \ - (per_cpu_ptr(mib[!in_softirq()], _smp_processor_id())->mibs[field]++) + (per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id())->mibs[field]++) #define SNMP_DEC_STATS(mib, field) \ - (per_cpu_ptr(mib[!in_softirq()], _smp_processor_id())->mibs[field]--) + (per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id())->mibs[field]--) #define SNMP_ADD_STATS_BH(mib, field, addend) \ - (per_cpu_ptr(mib[0], _smp_processor_id())->mibs[field] += addend) + (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field] += addend) #define SNMP_ADD_STATS_USER(mib, field, addend) \ - (per_cpu_ptr(mib[1], _smp_processor_id())->mibs[field] += addend) + (per_cpu_ptr(mib[1], raw_smp_processor_id())->mibs[field] += addend) #endif diff --git a/kernel/module.c b/kernel/module.c index 83b3d37..a566745 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -379,7 +379,7 @@ static void module_unload_init(struct module *mod) for (i = 0; i < NR_CPUS; i++) local_set(&mod->ref[i].count, 0); /* Hold reference count during initialization. */ - local_set(&mod->ref[_smp_processor_id()].count, 1); + local_set(&mod->ref[raw_smp_processor_id()].count, 1); /* Backwards compatibility macros put refcount during init. */ mod->waiter = current; } diff --git a/kernel/power/smp.c b/kernel/power/smp.c index cba3584b..457c230 100644 --- a/kernel/power/smp.c +++ b/kernel/power/smp.c @@ -48,11 +48,11 @@ void disable_nonboot_cpus(void) { oldmask = current->cpus_allowed; set_cpus_allowed(current, cpumask_of_cpu(0)); - printk("Freezing CPUs (at %d)", _smp_processor_id()); + printk("Freezing CPUs (at %d)", raw_smp_processor_id()); current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ); printk("..."); - BUG_ON(_smp_processor_id() != 0); + BUG_ON(raw_smp_processor_id() != 0); /* FIXME: for this to work, all the CPUs must be running * "idle" thread (or we deadlock). Is that guaranteed? */ diff --git a/kernel/sched.c b/kernel/sched.c index f12a0c8..deca041 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3814,7 +3814,7 @@ EXPORT_SYMBOL(yield); */ void __sched io_schedule(void) { - struct runqueue *rq = &per_cpu(runqueues, _smp_processor_id()); + struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id()); atomic_inc(&rq->nr_iowait); schedule(); @@ -3825,7 +3825,7 @@ EXPORT_SYMBOL(io_schedule); long __sched io_schedule_timeout(long timeout) { - struct runqueue *rq = &per_cpu(runqueues, _smp_processor_id()); + struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id()); long ret; atomic_inc(&rq->nr_iowait); diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 6116b25..84a9d18 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -100,7 +100,7 @@ static int stop_machine(void) stopmachine_state = STOPMACHINE_WAIT; for_each_online_cpu(i) { - if (i == _smp_processor_id()) + if (i == raw_smp_processor_id()) continue; ret = kernel_thread(stopmachine, (void *)(long)i,CLONE_KERNEL); if (ret < 0) @@ -182,7 +182,7 @@ struct task_struct *__stop_machine_run(int (*fn)(void *), void *data, /* If they don't care which CPU fn runs on, bind to any online one. */ if (cpu == NR_CPUS) - cpu = _smp_processor_id(); + cpu = raw_smp_processor_id(); p = kthread_create(do_stop, &smdata, "kstopmachine"); if (!IS_ERR(p)) { diff --git a/lib/Makefile b/lib/Makefile index 9eccea9..5f10cb8 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -20,6 +20,7 @@ lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o +obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o ifneq ($(CONFIG_HAVE_DEC_LOCK),y) lib-y += dec_and_lock.o diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c index 99b0ae3..bd2bc5d 100644 --- a/lib/kernel_lock.c +++ b/lib/kernel_lock.c @@ -9,61 +9,6 @@ #include #include -#if defined(CONFIG_PREEMPT) && defined(__smp_processor_id) && \ - defined(CONFIG_DEBUG_PREEMPT) - -/* - * Debugging check. - */ -unsigned int smp_processor_id(void) -{ - unsigned long preempt_count = preempt_count(); - int this_cpu = __smp_processor_id(); - cpumask_t this_mask; - - if (likely(preempt_count)) - goto out; - - if (irqs_disabled()) - goto out; - - /* - * Kernel threads bound to a single CPU can safely use - * smp_processor_id(): - */ - this_mask = cpumask_of_cpu(this_cpu); - - if (cpus_equal(current->cpus_allowed, this_mask)) - goto out; - - /* - * It is valid to assume CPU-locality during early bootup: - */ - if (system_state != SYSTEM_RUNNING) - goto out; - - /* - * Avoid recursion: - */ - preempt_disable(); - - if (!printk_ratelimit()) - goto out_enable; - - printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] code: %s/%d\n", preempt_count(), current->comm, current->pid); - print_symbol("caller is %s\n", (long)__builtin_return_address(0)); - dump_stack(); - -out_enable: - preempt_enable_no_resched(); -out: - return this_cpu; -} - -EXPORT_SYMBOL(smp_processor_id); - -#endif /* PREEMPT && __smp_processor_id && DEBUG_PREEMPT */ - #ifdef CONFIG_PREEMPT_BKL /* * The 'big kernel semaphore' diff --git a/lib/smp_processor_id.c b/lib/smp_processor_id.c new file mode 100644 index 0000000..42c08ef --- /dev/null +++ b/lib/smp_processor_id.c @@ -0,0 +1,55 @@ +/* + * lib/smp_processor_id.c + * + * DEBUG_PREEMPT variant of smp_processor_id(). + */ +#include +#include + +unsigned int debug_smp_processor_id(void) +{ + unsigned long preempt_count = preempt_count(); + int this_cpu = raw_smp_processor_id(); + cpumask_t this_mask; + + if (likely(preempt_count)) + goto out; + + if (irqs_disabled()) + goto out; + + /* + * Kernel threads bound to a single CPU can safely use + * smp_processor_id(): + */ + this_mask = cpumask_of_cpu(this_cpu); + + if (cpus_equal(current->cpus_allowed, this_mask)) + goto out; + + /* + * It is valid to assume CPU-locality during early bootup: + */ + if (system_state != SYSTEM_RUNNING) + goto out; + + /* + * Avoid recursion: + */ + preempt_disable(); + + if (!printk_ratelimit()) + goto out_enable; + + printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] code: %s/%d\n", preempt_count(), current->comm, current->pid); + print_symbol("caller is %s\n", (long)__builtin_return_address(0)); + dump_stack(); + +out_enable: + preempt_enable_no_resched(); +out: + return this_cpu; +} + +EXPORT_SYMBOL(debug_smp_processor_id); + -- cgit v0.10.2 From b15e0905f2b9964fc7426fecab57445e96021b61 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Tue, 21 Jun 2005 17:14:35 -0700 Subject: [PATCH] vmscan: notice slab shrinking Fix a problem identified by Andrea Arcangeli kswapd will set a zone into all_unreclaimable state if it sees that we're not successfully reclaiming LRU pages. But that fails to notice that we're successfully reclaiming slab obects, so we can set all_unreclaimable too soon. So change shrink_slab() to return a success indication if it actually reclaimed some objects, and don't assume that the zone is all_unreclaimable if that is true. This means that we won't enter all_unreclaimable state if we are successfully freeing slab objects but we're not yet actually freeing slab pages, due to internal fragmentation. (hm, this has a shortcoming. We could be successfully freeing ZONE_NORMAL slab objects while being really oom on ZONE_DMA. If that happens then kswapd might burn a lot of CPU. But given that there might be some slab objects in ZONE_DMA, perhaps that is appropriate.) Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmscan.c b/mm/vmscan.c index 269eded..c62cadc 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -180,17 +180,20 @@ EXPORT_SYMBOL(remove_shrinker); * `lru_pages' represents the number of on-LRU pages in all the zones which * are eligible for the caller's allocation attempt. It is used for balancing * slab reclaim versus page reclaim. + * + * Returns the number of slab objects which we shrunk. */ static int shrink_slab(unsigned long scanned, unsigned int gfp_mask, unsigned long lru_pages) { struct shrinker *shrinker; + int ret = 0; if (scanned == 0) scanned = SWAP_CLUSTER_MAX; if (!down_read_trylock(&shrinker_rwsem)) - return 0; + return 1; /* Assume we'll be able to shrink next time */ list_for_each_entry(shrinker, &shrinker_list, list) { unsigned long long delta; @@ -209,10 +212,14 @@ static int shrink_slab(unsigned long scanned, unsigned int gfp_mask, while (total_scan >= SHRINK_BATCH) { long this_scan = SHRINK_BATCH; int shrink_ret; + int nr_before; + nr_before = (*shrinker->shrinker)(0, gfp_mask); shrink_ret = (*shrinker->shrinker)(this_scan, gfp_mask); if (shrink_ret == -1) break; + if (shrink_ret < nr_before) + ret += nr_before - shrink_ret; mod_page_state(slabs_scanned, this_scan); total_scan -= this_scan; @@ -222,7 +229,7 @@ static int shrink_slab(unsigned long scanned, unsigned int gfp_mask, shrinker->nr += total_scan; } up_read(&shrinker_rwsem); - return 0; + return ret; } /* Called without lock on whether page is mapped, so answer is unstable */ @@ -1079,6 +1086,7 @@ scan: */ for (i = 0; i <= end_zone; i++) { struct zone *zone = pgdat->node_zones + i; + int nr_slab; if (zone->present_pages == 0) continue; @@ -1100,14 +1108,15 @@ scan: sc.swap_cluster_max = nr_pages? nr_pages : SWAP_CLUSTER_MAX; shrink_zone(zone, &sc); reclaim_state->reclaimed_slab = 0; - shrink_slab(sc.nr_scanned, GFP_KERNEL, lru_pages); + nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL, + lru_pages); sc.nr_reclaimed += reclaim_state->reclaimed_slab; total_reclaimed += sc.nr_reclaimed; total_scanned += sc.nr_scanned; if (zone->all_unreclaimable) continue; - if (zone->pages_scanned >= (zone->nr_active + - zone->nr_inactive) * 4) + if (nr_slab == 0 && zone->pages_scanned >= + (zone->nr_active + zone->nr_inactive) * 4) zone->all_unreclaimable = 1; /* * If we've done a decent amount of scanning and -- cgit v0.10.2 From e798c6e87b64d9fdbd5e9f757b1c033223763d9f Mon Sep 17 00:00:00 2001 From: Prasanna Meda Date: Tue, 21 Jun 2005 17:14:36 -0700 Subject: [PATCH] madvise: do not split the maps This attempts to avoid splittings when it is not needed, that is when vm_flags are same as new flags. The idea is from the <2.6.11 mlock_fixup and others. This will provide base for the next madvise merging patch. Signed-off-by: Prasanna Meda Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/madvise.c b/mm/madvise.c index 944b5e5..75b81ad 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -19,6 +19,21 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, { struct mm_struct * mm = vma->vm_mm; int error = 0; + int new_flags = vma->vm_flags & ~VM_READHINTMASK; + + switch (behavior) { + case MADV_SEQUENTIAL: + new_flags |= VM_SEQ_READ; + break; + case MADV_RANDOM: + new_flags |= VM_RAND_READ; + break; + default: + break; + } + + if (new_flags == vma->vm_flags) + goto out; if (start != vma->vm_start) { error = split_vma(mm, vma, start, 1); @@ -36,17 +51,7 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, * vm_flags is protected by the mmap_sem held in write mode. */ VM_ClearReadHint(vma); - - switch (behavior) { - case MADV_SEQUENTIAL: - vma->vm_flags |= VM_SEQ_READ; - break; - case MADV_RANDOM: - vma->vm_flags |= VM_RAND_READ; - break; - default: - break; - } + vma->vm_flags = new_flags; out: if (error == -ENOMEM) -- cgit v0.10.2 From 05b7438475ddbac47e75506913d44550f0e75938 Mon Sep 17 00:00:00 2001 From: Prasanna Meda Date: Tue, 21 Jun 2005 17:14:37 -0700 Subject: [PATCH] madvise: merge the maps This attempts to merge back the split maps. This code is mostly copied from Chrisw's mlock merging from post 2.6.11 trees. The only difference is in munmapped_error handling. Also passed prev to willneed/dontneed, eventhogh they do not handle it now, since I felt it will be cleaner, instead of handling prev in madvise_vma in some cases and in subfunction in some cases. Signed-off-by: Prasanna Meda Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/madvise.c b/mm/madvise.c index 75b81ad..e310805 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -8,17 +8,20 @@ #include #include #include +#include #include /* * We can potentially split a vm area into separate * areas, each area with its own behavior. */ -static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, - unsigned long end, int behavior) +static long madvise_behavior(struct vm_area_struct * vma, + struct vm_area_struct **prev, + unsigned long start, unsigned long end, int behavior) { struct mm_struct * mm = vma->vm_mm; int error = 0; + pgoff_t pgoff; int new_flags = vma->vm_flags & ~VM_READHINTMASK; switch (behavior) { @@ -32,8 +35,20 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, break; } - if (new_flags == vma->vm_flags) - goto out; + if (new_flags == vma->vm_flags) { + *prev = vma; + goto success; + } + + pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); + *prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma, + vma->vm_file, pgoff, vma_policy(vma)); + if (*prev) { + vma = *prev; + goto success; + } + + *prev = vma; if (start != vma->vm_start) { error = split_vma(mm, vma, start, 1); @@ -56,6 +71,7 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, out: if (error == -ENOMEM) error = -EAGAIN; +success: return error; } @@ -63,6 +79,7 @@ out: * Schedule all required I/O operations. Do not wait for completion. */ static long madvise_willneed(struct vm_area_struct * vma, + struct vm_area_struct ** prev, unsigned long start, unsigned long end) { struct file *file = vma->vm_file; @@ -70,6 +87,7 @@ static long madvise_willneed(struct vm_area_struct * vma, if (!file) return -EBADF; + *prev = vma; start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; if (end > vma->vm_end) end = vma->vm_end; @@ -100,8 +118,10 @@ static long madvise_willneed(struct vm_area_struct * vma, * dirty pages is already available as msync(MS_INVALIDATE). */ static long madvise_dontneed(struct vm_area_struct * vma, + struct vm_area_struct ** prev, unsigned long start, unsigned long end) { + *prev = vma; if ((vma->vm_flags & VM_LOCKED) || is_vm_hugetlb_page(vma)) return -EINVAL; @@ -116,8 +136,8 @@ static long madvise_dontneed(struct vm_area_struct * vma, return 0; } -static long madvise_vma(struct vm_area_struct * vma, unsigned long start, - unsigned long end, int behavior) +static long madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev, + unsigned long start, unsigned long end, int behavior) { long error = -EBADF; @@ -125,15 +145,15 @@ static long madvise_vma(struct vm_area_struct * vma, unsigned long start, case MADV_NORMAL: case MADV_SEQUENTIAL: case MADV_RANDOM: - error = madvise_behavior(vma, start, end, behavior); + error = madvise_behavior(vma, prev, start, end, behavior); break; case MADV_WILLNEED: - error = madvise_willneed(vma, start, end); + error = madvise_willneed(vma, prev, start, end); break; case MADV_DONTNEED: - error = madvise_dontneed(vma, start, end); + error = madvise_dontneed(vma, prev, start, end); break; default: @@ -180,8 +200,8 @@ static long madvise_vma(struct vm_area_struct * vma, unsigned long start, */ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior) { - unsigned long end; - struct vm_area_struct * vma; + unsigned long end, tmp; + struct vm_area_struct * vma, *prev; int unmapped_error = 0; int error = -EINVAL; size_t len; @@ -207,40 +227,42 @@ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior) /* * If the interval [start,end) covers some unmapped address * ranges, just ignore them, but return -ENOMEM at the end. + * - different from the way of handling in mlock etc. */ - vma = find_vma(current->mm, start); + vma = find_vma_prev(current->mm, start, &prev); + if (!vma && prev) + vma = prev->vm_next; for (;;) { /* Still start < end. */ error = -ENOMEM; if (!vma) goto out; - /* Here start < vma->vm_end. */ + /* Here start < (end|vma->vm_end). */ if (start < vma->vm_start) { unmapped_error = -ENOMEM; start = vma->vm_start; + if (start >= end) + goto out; } - /* Here vma->vm_start <= start < vma->vm_end. */ - if (end <= vma->vm_end) { - if (start < end) { - error = madvise_vma(vma, start, end, - behavior); - if (error) - goto out; - } - error = unmapped_error; - goto out; - } + /* Here vma->vm_start <= start < (end|vma->vm_end) */ + tmp = vma->vm_end; + if (end < tmp) + tmp = end; - /* Here vma->vm_start <= start < vma->vm_end < end. */ - error = madvise_vma(vma, start, vma->vm_end, behavior); + /* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */ + error = madvise_vma(vma, &prev, start, tmp, behavior); if (error) goto out; - start = vma->vm_end; - vma = vma->vm_next; + start = tmp; + if (start < prev->vm_end) + start = prev->vm_end; + error = unmapped_error; + if (start >= end) + goto out; + vma = prev->vm_next; } - out: up_write(¤t->mm->mmap_sem); return error; -- cgit v0.10.2 From 295ab93497ec703f7d6eaf0787dd9768b83035fe Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Tue, 21 Jun 2005 17:14:38 -0700 Subject: [PATCH] mm: add /proc/zoneinfo Add /proc/zoneinfo file to display information about memory zones. Useful to analyze VM behaviour. Signed-off-by: Nikita Danilov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index a60a3b3..63a9fbf 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -219,6 +219,19 @@ static struct file_operations fragmentation_file_operations = { .release = seq_release, }; +extern struct seq_operations zoneinfo_op; +static int zoneinfo_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &zoneinfo_op); +} + +static struct file_operations proc_zoneinfo_file_operations = { + .open = zoneinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static int version_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -589,6 +602,7 @@ void __init proc_misc_init(void) create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); + create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations); create_seq_entry("diskstats", 0, &proc_diskstats_operations); #ifdef CONFIG_MODULES create_seq_entry("modules", 0, &proc_modules_operations); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index b1061b1..40169f0 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1853,6 +1853,115 @@ struct seq_operations fragmentation_op = { .show = frag_show, }; +/* + * Output information about zones in @pgdat. + */ +static int zoneinfo_show(struct seq_file *m, void *arg) +{ + pg_data_t *pgdat = arg; + struct zone *zone; + struct zone *node_zones = pgdat->node_zones; + unsigned long flags; + + for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; zone++) { + int i; + + if (!zone->present_pages) + continue; + + spin_lock_irqsave(&zone->lock, flags); + seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name); + seq_printf(m, + "\n pages free %lu" + "\n min %lu" + "\n low %lu" + "\n high %lu" + "\n active %lu" + "\n inactive %lu" + "\n scanned %lu (a: %lu i: %lu)" + "\n spanned %lu" + "\n present %lu", + zone->free_pages, + zone->pages_min, + zone->pages_low, + zone->pages_high, + zone->nr_active, + zone->nr_inactive, + zone->pages_scanned, + zone->nr_scan_active, zone->nr_scan_inactive, + zone->spanned_pages, + zone->present_pages); + seq_printf(m, + "\n protection: (%lu", + zone->lowmem_reserve[0]); + for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++) + seq_printf(m, ", %lu", zone->lowmem_reserve[i]); + seq_printf(m, + ")" + "\n pagesets"); + for (i = 0; i < ARRAY_SIZE(zone->pageset); i++) { + struct per_cpu_pageset *pageset; + int j; + + pageset = &zone->pageset[i]; + for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) { + if (pageset->pcp[j].count) + break; + } + if (j == ARRAY_SIZE(pageset->pcp)) + continue; + for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) { + seq_printf(m, + "\n cpu: %i pcp: %i" + "\n count: %i" + "\n low: %i" + "\n high: %i" + "\n batch: %i", + i, j, + pageset->pcp[j].count, + pageset->pcp[j].low, + pageset->pcp[j].high, + pageset->pcp[j].batch); + } +#ifdef CONFIG_NUMA + seq_printf(m, + "\n numa_hit: %lu" + "\n numa_miss: %lu" + "\n numa_foreign: %lu" + "\n interleave_hit: %lu" + "\n local_node: %lu" + "\n other_node: %lu", + pageset->numa_hit, + pageset->numa_miss, + pageset->numa_foreign, + pageset->interleave_hit, + pageset->local_node, + pageset->other_node); +#endif + } + seq_printf(m, + "\n all_unreclaimable: %u" + "\n prev_priority: %i" + "\n temp_priority: %i" + "\n start_pfn: %lu", + zone->all_unreclaimable, + zone->prev_priority, + zone->temp_priority, + zone->zone_start_pfn); + spin_unlock_irqrestore(&zone->lock, flags); + seq_putc(m, '\n'); + } + return 0; +} + +struct seq_operations zoneinfo_op = { + .start = frag_start, /* iterate over all zones. The same as in + * fragmentation. */ + .next = frag_next, + .stop = frag_stop, + .show = zoneinfo_show, +}; + static char *vmstat_text[] = { "nr_dirty", "nr_writeback", @@ -2058,10 +2167,10 @@ static void setup_per_zone_pages_min(void) min_pages = 128; zone->pages_min = min_pages; } else { - /* if it's a lowmem zone, reserve a number of pages + /* if it's a lowmem zone, reserve a number of pages * proportionate to the zone's size. */ - zone->pages_min = (pages_min * zone->present_pages) / + zone->pages_min = (pages_min * zone->present_pages) / lowmem_pages; } -- cgit v0.10.2 From bfbb38fb808ac23ef44472d05d9bb36edfb49ed0 Mon Sep 17 00:00:00 2001 From: Martin Hicks Date: Tue, 21 Jun 2005 17:14:40 -0700 Subject: [PATCH] VM: add may_swap flag to scan_control Here's the next round of these patches. These are totally different in an attempt to meet the "simpler" request after the last patches. For reference the earlier threads are: http://marc.theaimsgroup.com/?l=linux-kernel&m=110839604924587&w=2 http://marc.theaimsgroup.com/?l=linux-mm&m=111461480721249&w=2 This set of patches replaces my other vm- patches that are currently in -mm. So they're against 2.6.12-rc5-mm1 about half way through the -mm patchset. As I said already this patch is a lot simpler. The reclaim is turned on or off on a per-zone basis using a syscall. I haven't tested the x86 syscall, so it might be wrong. It uses the existing reclaim/pageout code with the small addition of a may_swap flag to scan_control (patch 1/4). I also added __GFP_NORECLAIM (patch 3/4) so that certain allocation types can be flagged to never cause reclaim. This was a deficiency that was in all of my earlier patch sets. Previously, doing a big buffered read would fill one zone with page cache and then start to reclaim from that same zone, leaving the other zones untouched. Adding some extra throttling on the reclaim was also required (patch 4/4). Without the machine would grind to a crawl when doing a "make -j" kernel build. Even with this patch the System Time is higher on average, but it seems tolerable. Here are some numbers for kernbench runs on a 2-node, 4cpu, 8Gig RAM Altix in the "make -j" run: wall user sys %cpu ctx sw. sleeps ---- ---- --- ---- ------ ------ No patch 1009 1384 847 258 298170 504402 w/patch, no reclaim 880 1376 667 288 254064 396745 w/patch & reclaim 1079 1385 926 252 291625 548873 These numbers are the average of 2 runs of 3 "make -j" runs done right after system boot. Run-to-run variability for "make -j" is huge, so these numbers aren't terribly useful except to seee that with reclaim the benchmark still finishes in a reasonable amount of time. I also looked at the NUMA hit/miss stats for the "make -j" runs and the reclaim doesn't make any difference when the machine is thrashing away. Doing a "make -j8" on a single node that is filled with page cache pages takes 700 seconds with reclaim turned on and 735 seconds without reclaim (due to remote memory accesses). The simple zone_reclaim syscall program is at http://www.bork.org/~mort/sgi/zone_reclaim.c This patch: This adds an extra switch to the scan_control struct. It simply lets the reclaim code know if its allowed to swap pages out. This was required for a simple per-zone reclaimer. Without this addition pages would be swapped out as soon as a zone ran out of memory and the early reclaim kicked in. Signed-off-by: Martin Hicks Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmscan.c b/mm/vmscan.c index c62cadc..6379ddb 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -74,6 +74,9 @@ struct scan_control { int may_writepage; + /* Can pages be swapped as part of reclaim? */ + int may_swap; + /* This context's SWAP_CLUSTER_MAX. If freeing memory for * suspend, we effectively ignore SWAP_CLUSTER_MAX. * In this context, it doesn't matter that we scan the @@ -414,7 +417,7 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) * Anonymous process memory has backing store? * Try to allocate it some swap space here. */ - if (PageAnon(page) && !PageSwapCache(page)) { + if (PageAnon(page) && !PageSwapCache(page) && sc->may_swap) { if (!add_to_swap(page)) goto activate_locked; } @@ -927,6 +930,7 @@ int try_to_free_pages(struct zone **zones, sc.gfp_mask = gfp_mask; sc.may_writepage = 0; + sc.may_swap = 1; inc_page_state(allocstall); @@ -1027,6 +1031,7 @@ loop_again: total_reclaimed = 0; sc.gfp_mask = GFP_KERNEL; sc.may_writepage = 0; + sc.may_swap = 1; sc.nr_mapped = read_page_state(nr_mapped); inc_page_state(pageoutrun); -- cgit v0.10.2 From 753ee728964e5afb80c17659cc6c3a6fd0a42fe0 Mon Sep 17 00:00:00 2001 From: Martin Hicks Date: Tue, 21 Jun 2005 17:14:41 -0700 Subject: [PATCH] VM: early zone reclaim This is the core of the (much simplified) early reclaim. The goal of this patch is to reclaim some easily-freed pages from a zone before falling back onto another zone. One of the major uses of this is NUMA machines. With the default allocator behavior the allocator would look for memory in another zone, which might be off-node, before trying to reclaim from the current zone. This adds a zone tuneable to enable early zone reclaim. It is selected on a per-zone basis and is turned on/off via syscall. Adding some extra throttling on the reclaim was also required (patch 4/4). Without the machine would grind to a crawl when doing a "make -j" kernel build. Even with this patch the System Time is higher on average, but it seems tolerable. Here are some numbers for kernbench runs on a 2-node, 4cpu, 8Gig RAM Altix in the "make -j" run: wall user sys %cpu ctx sw. sleeps ---- ---- --- ---- ------ ------ No patch 1009 1384 847 258 298170 504402 w/patch, no reclaim 880 1376 667 288 254064 396745 w/patch & reclaim 1079 1385 926 252 291625 548873 These numbers are the average of 2 runs of 3 "make -j" runs done right after system boot. Run-to-run variability for "make -j" is huge, so these numbers aren't terribly useful except to seee that with reclaim the benchmark still finishes in a reasonable amount of time. I also looked at the NUMA hit/miss stats for the "make -j" runs and the reclaim doesn't make any difference when the machine is thrashing away. Doing a "make -j8" on a single node that is filled with page cache pages takes 700 seconds with reclaim turned on and 735 seconds without reclaim (due to remote memory accesses). The simple zone_reclaim syscall program is at http://www.bork.org/~mort/sgi/zone_reclaim.c Signed-off-by: Martin Hicks Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index 6cd1ed3..d408afa 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S @@ -251,7 +251,7 @@ ENTRY(sys_call_table) .long sys_io_submit .long sys_io_cancel .long sys_fadvise64 /* 250 */ - .long sys_ni_syscall + .long sys_set_zone_reclaim .long sys_exit_group .long sys_lookup_dcookie .long sys_epoll_create diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index d99316c..b1d5d3d 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1579,7 +1579,7 @@ sys_call_table: data8 sys_keyctl data8 sys_ni_syscall data8 sys_ni_syscall // 1275 - data8 sys_ni_syscall + data8 sys_set_zone_reclaim data8 sys_ni_syscall data8 sys_ni_syscall data8 sys_ni_syscall diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 61bcc1b..176413f 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -256,7 +256,7 @@ #define __NR_io_submit 248 #define __NR_io_cancel 249 #define __NR_fadvise64 250 - +#define __NR_set_zone_reclaim 251 #define __NR_exit_group 252 #define __NR_lookup_dcookie 253 #define __NR_epoll_create 254 diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index 33e26c5..f7f43ec 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -263,6 +263,7 @@ #define __NR_add_key 1271 #define __NR_request_key 1272 #define __NR_keyctl 1273 +#define __NR_set_zone_reclaim 1276 #ifdef __KERNEL__ diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index beacd93..dfc2452 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -145,6 +145,12 @@ struct zone { int all_unreclaimable; /* All pages pinned */ /* + * Does the allocator try to reclaim pages from the zone as soon + * as it fails a watermark_ok() in __alloc_pages? + */ + int reclaim_pages; + + /* * prev_priority holds the scanning priority for this zone. It is * defined as the scanning priority at which we achieved our reclaim * target at the previous try_to_free_pages() or balance_pgdat() diff --git a/include/linux/swap.h b/include/linux/swap.h index 3bbc41b..0d21e682 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -173,6 +173,7 @@ extern void swap_setup(void); /* linux/mm/vmscan.c */ extern int try_to_free_pages(struct zone **, unsigned int, unsigned int); +extern int zone_reclaim(struct zone *, unsigned int, unsigned int); extern int shrink_all_memory(int); extern int vm_swappiness; diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 0dda70e..6f15bea 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -77,6 +77,7 @@ cond_syscall(sys_request_key); cond_syscall(sys_keyctl); cond_syscall(compat_sys_keyctl); cond_syscall(compat_sys_socketcall); +cond_syscall(sys_set_zone_reclaim); /* arch-specific weak syscall entries */ cond_syscall(sys_pciconfig_read); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 40169f0..3c0f69d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -724,6 +724,14 @@ int zone_watermark_ok(struct zone *z, int order, unsigned long mark, return 1; } +static inline int +should_reclaim_zone(struct zone *z, unsigned int gfp_mask) +{ + if (!z->reclaim_pages) + return 0; + return 1; +} + /* * This is the 'heart' of the zoned buddy allocator. */ @@ -760,17 +768,32 @@ __alloc_pages(unsigned int __nocast gfp_mask, unsigned int order, classzone_idx = zone_idx(zones[0]); - restart: +restart: /* Go through the zonelist once, looking for a zone with enough free */ for (i = 0; (z = zones[i]) != NULL; i++) { - - if (!zone_watermark_ok(z, order, z->pages_low, - classzone_idx, 0, 0)) - continue; + int do_reclaim = should_reclaim_zone(z, gfp_mask); if (!cpuset_zone_allowed(z)) continue; + /* + * If the zone is to attempt early page reclaim then this loop + * will try to reclaim pages and check the watermark a second + * time before giving up and falling back to the next zone. + */ +zone_reclaim_retry: + if (!zone_watermark_ok(z, order, z->pages_low, + classzone_idx, 0, 0)) { + if (!do_reclaim) + continue; + else { + zone_reclaim(z, gfp_mask, order); + /* Only try reclaim once */ + do_reclaim = 0; + goto zone_reclaim_retry; + } + } + page = buffered_rmqueue(z, order, gfp_mask); if (page) goto got_pg; diff --git a/mm/vmscan.c b/mm/vmscan.c index 6379ddb..7da8469 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1323,3 +1323,67 @@ static int __init kswapd_init(void) } module_init(kswapd_init) + + +/* + * Try to free up some pages from this zone through reclaim. + */ +int zone_reclaim(struct zone *zone, unsigned int gfp_mask, unsigned int order) +{ + struct scan_control sc; + int nr_pages = 1 << order; + int total_reclaimed = 0; + + /* The reclaim may sleep, so don't do it if sleep isn't allowed */ + if (!(gfp_mask & __GFP_WAIT)) + return 0; + if (zone->all_unreclaimable) + return 0; + + sc.gfp_mask = gfp_mask; + sc.may_writepage = 0; + sc.may_swap = 0; + sc.nr_mapped = read_page_state(nr_mapped); + sc.nr_scanned = 0; + sc.nr_reclaimed = 0; + /* scan at the highest priority */ + sc.priority = 0; + + if (nr_pages > SWAP_CLUSTER_MAX) + sc.swap_cluster_max = nr_pages; + else + sc.swap_cluster_max = SWAP_CLUSTER_MAX; + + shrink_zone(zone, &sc); + total_reclaimed = sc.nr_reclaimed; + + return total_reclaimed; +} + +asmlinkage long sys_set_zone_reclaim(unsigned int node, unsigned int zone, + unsigned int state) +{ + struct zone *z; + int i; + + if (node >= MAX_NUMNODES || !node_online(node)) + return -EINVAL; + + /* This will break if we ever add more zones */ + if (!(zone & (1<node_zones[i]; + + if (state) + z->reclaim_pages = 1; + else + z->reclaim_pages = 0; + } + + return 0; +} -- cgit v0.10.2 From 0c35bbadc59f5ed105c34471143eceb4c0dd9c95 Mon Sep 17 00:00:00 2001 From: Martin Hicks Date: Tue, 21 Jun 2005 17:14:42 -0700 Subject: [PATCH] VM: add __GFP_NORECLAIM When using the early zone reclaim, it was noticed that allocating new pages that should be spread across the whole system caused eviction of local pages. This adds a new GFP flag to prevent early reclaim from happening during certain allocation attempts. The example that is implemented here is for page cache pages. We want page cache pages to be spread across the whole system, and we don't want page cache pages to evict other pages to get local memory. Signed-off-by: Martin Hicks Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/gfp.h b/include/linux/gfp.h index af7407e..208535f 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -39,6 +39,7 @@ struct vm_area_struct; #define __GFP_COMP 0x4000u /* Add compound page metadata */ #define __GFP_ZERO 0x8000u /* Return zeroed page on success */ #define __GFP_NOMEMALLOC 0x10000u /* Don't use emergency reserves */ +#define __GFP_NORECLAIM 0x20000u /* No realy zone reclaim during allocation */ #define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */ #define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1) @@ -47,7 +48,7 @@ struct vm_area_struct; #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \ __GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \ __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \ - __GFP_NOMEMALLOC) + __GFP_NOMEMALLOC|__GFP_NORECLAIM) #define GFP_ATOMIC (__GFP_HIGH) #define GFP_NOIO (__GFP_WAIT) diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 0422031..d9a2564 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -52,12 +52,12 @@ void release_pages(struct page **pages, int nr, int cold); static inline struct page *page_cache_alloc(struct address_space *x) { - return alloc_pages(mapping_gfp_mask(x), 0); + return alloc_pages(mapping_gfp_mask(x)|__GFP_NORECLAIM, 0); } static inline struct page *page_cache_alloc_cold(struct address_space *x) { - return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0); + return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD|__GFP_NORECLAIM, 0); } typedef int filler_t(void *, struct page *); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 3c0f69d..a9da20b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -729,6 +729,8 @@ should_reclaim_zone(struct zone *z, unsigned int gfp_mask) { if (!z->reclaim_pages) return 0; + if (gfp_mask & __GFP_NORECLAIM) + return 0; return 1; } -- cgit v0.10.2 From 1e7e5a9048b30c57ba1ddaa6cdf59b21b65cde99 Mon Sep 17 00:00:00 2001 From: Martin Hicks Date: Tue, 21 Jun 2005 17:14:43 -0700 Subject: [PATCH] VM: rate limit early reclaim When early zone reclaim is turned on the LRU is scanned more frequently when a zone is low on memory. This limits when the zone reclaim can be called by skipping the scan if another thread (either via kswapd or sync reclaim) is already reclaiming from the zone. Signed-off-by: Martin Hicks Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index dfc2452..18fed8b 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -149,6 +149,8 @@ struct zone { * as it fails a watermark_ok() in __alloc_pages? */ int reclaim_pages; + /* A count of how many reclaimers are scanning this zone */ + atomic_t reclaim_in_progress; /* * prev_priority holds the scanning priority for this zone. It is diff --git a/mm/page_alloc.c b/mm/page_alloc.c index a9da20b..2019c1b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1738,6 +1738,7 @@ static void __init free_area_init_core(struct pglist_data *pgdat, zone->nr_scan_inactive = 0; zone->nr_active = 0; zone->nr_inactive = 0; + atomic_set(&zone->reclaim_in_progress, -1); if (!size) continue; diff --git a/mm/vmscan.c b/mm/vmscan.c index 7da8469..24da725 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -900,7 +900,9 @@ shrink_caches(struct zone **zones, struct scan_control *sc) if (zone->all_unreclaimable && sc->priority != DEF_PRIORITY) continue; /* Let kswapd poll it */ + atomic_inc(&zone->reclaim_in_progress); shrink_zone(zone, sc); + atomic_dec(&zone->reclaim_in_progress); } } @@ -1111,7 +1113,9 @@ scan: sc.nr_reclaimed = 0; sc.priority = priority; sc.swap_cluster_max = nr_pages? nr_pages : SWAP_CLUSTER_MAX; + atomic_inc(&zone->reclaim_in_progress); shrink_zone(zone, &sc); + atomic_dec(&zone->reclaim_in_progress); reclaim_state->reclaimed_slab = 0; nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL, lru_pages); @@ -1354,9 +1358,15 @@ int zone_reclaim(struct zone *zone, unsigned int gfp_mask, unsigned int order) else sc.swap_cluster_max = SWAP_CLUSTER_MAX; + /* Don't reclaim the zone if there are other reclaimers active */ + if (!atomic_inc_and_test(&zone->reclaim_in_progress)) + goto out; + shrink_zone(zone, &sc); total_reclaimed = sc.nr_reclaimed; + out: + atomic_dec(&zone->reclaim_in_progress); return total_reclaimed; } -- cgit v0.10.2 From 63551ae0feaaa23807ebea60de1901564bbef32e Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 21 Jun 2005 17:14:44 -0700 Subject: [PATCH] Hugepage consolidation A lot of the code in arch/*/mm/hugetlbpage.c is quite similar. This patch attempts to consolidate a lot of the code across the arch's, putting the combined version in mm/hugetlb.c. There are a couple of uglyish hacks in order to covert all the hugepage archs, but the result is a very large reduction in the total amount of code. It also means things like hugepage lazy allocation could be implemented in one place, instead of six. Tested, at least a little, on ppc64, i386 and x86_64. Notes: - this patch changes the meaning of set_huge_pte() to be more analagous to set_pte() - does SH4 need s special huge_ptep_get_and_clear()?? Acked-by: William Lee Irwin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c index 171fc92..5aa0600 100644 --- a/arch/i386/mm/hugetlbpage.c +++ b/arch/i386/mm/hugetlbpage.c @@ -18,7 +18,7 @@ #include #include -static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) +pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; pud_t *pud; @@ -30,7 +30,7 @@ static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) return (pte_t *) pmd; } -static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) +pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; pud_t *pud; @@ -42,21 +42,6 @@ static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) return (pte_t *) pmd; } -static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, struct page *page, pte_t * page_table, int write_access) -{ - pte_t entry; - - add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE); - if (write_access) { - entry = - pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - } else - entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot)); - entry = pte_mkyoung(entry); - mk_pte_huge(entry); - set_pte(page_table, entry); -} - /* * This function checks for proper alignment of input addr and len parameters. */ @@ -69,77 +54,6 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len) return 0; } -int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, - struct vm_area_struct *vma) -{ - pte_t *src_pte, *dst_pte, entry; - struct page *ptepage; - unsigned long addr = vma->vm_start; - unsigned long end = vma->vm_end; - - while (addr < end) { - dst_pte = huge_pte_alloc(dst, addr); - if (!dst_pte) - goto nomem; - src_pte = huge_pte_offset(src, addr); - entry = *src_pte; - ptepage = pte_page(entry); - get_page(ptepage); - set_pte(dst_pte, entry); - add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); - addr += HPAGE_SIZE; - } - return 0; - -nomem: - return -ENOMEM; -} - -int -follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, - struct page **pages, struct vm_area_struct **vmas, - unsigned long *position, int *length, int i) -{ - unsigned long vpfn, vaddr = *position; - int remainder = *length; - - WARN_ON(!is_vm_hugetlb_page(vma)); - - vpfn = vaddr/PAGE_SIZE; - while (vaddr < vma->vm_end && remainder) { - - if (pages) { - pte_t *pte; - struct page *page; - - pte = huge_pte_offset(mm, vaddr); - - /* hugetlb should be locked, and hence, prefaulted */ - WARN_ON(!pte || pte_none(*pte)); - - page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)]; - - WARN_ON(!PageCompound(page)); - - get_page(page); - pages[i] = page; - } - - if (vmas) - vmas[i] = vma; - - vaddr += PAGE_SIZE; - ++vpfn; - --remainder; - ++i; - } - - *length = remainder; - *position = vaddr; - - return i; -} - #if 0 /* This is just for testing */ struct page * follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) @@ -204,83 +118,15 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address, } #endif -void unmap_hugepage_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) +void hugetlb_clean_stale_pgtable(pte_t *pte) { - struct mm_struct *mm = vma->vm_mm; - unsigned long address; - pte_t pte, *ptep; + pmd_t *pmd = (pmd_t *) pte; struct page *page; - BUG_ON(start & (HPAGE_SIZE - 1)); - BUG_ON(end & (HPAGE_SIZE - 1)); - - for (address = start; address < end; address += HPAGE_SIZE) { - ptep = huge_pte_offset(mm, address); - if (!ptep) - continue; - pte = ptep_get_and_clear(mm, address, ptep); - if (pte_none(pte)) - continue; - page = pte_page(pte); - put_page(page); - } - add_mm_counter(mm ,rss, -((end - start) >> PAGE_SHIFT)); - flush_tlb_range(vma, start, end); -} - -int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) -{ - struct mm_struct *mm = current->mm; - unsigned long addr; - int ret = 0; - - BUG_ON(vma->vm_start & ~HPAGE_MASK); - BUG_ON(vma->vm_end & ~HPAGE_MASK); - - spin_lock(&mm->page_table_lock); - for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { - unsigned long idx; - pte_t *pte = huge_pte_alloc(mm, addr); - struct page *page; - - if (!pte) { - ret = -ENOMEM; - goto out; - } - - if (!pte_none(*pte)) - continue; - - idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) - + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); - page = find_get_page(mapping, idx); - if (!page) { - /* charge the fs quota first */ - if (hugetlb_get_quota(mapping)) { - ret = -ENOMEM; - goto out; - } - page = alloc_huge_page(); - if (!page) { - hugetlb_put_quota(mapping); - ret = -ENOMEM; - goto out; - } - ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC); - if (! ret) { - unlock_page(page); - } else { - hugetlb_put_quota(mapping); - free_huge_page(page); - goto out; - } - } - set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); - } -out: - spin_unlock(&mm->page_table_lock); - return ret; + page = pmd_page(*pmd); + pmd_clear(pmd); + dec_page_state(nr_page_table_pages); + page_cache_release(page); } /* x86_64 also uses this file */ diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index df08ae7..e0a776a 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c @@ -24,7 +24,7 @@ unsigned int hpage_shift=HPAGE_SHIFT_DEFAULT; -static pte_t * +pte_t * huge_pte_alloc (struct mm_struct *mm, unsigned long addr) { unsigned long taddr = htlbpage_to_page(addr); @@ -43,7 +43,7 @@ huge_pte_alloc (struct mm_struct *mm, unsigned long addr) return pte; } -static pte_t * +pte_t * huge_pte_offset (struct mm_struct *mm, unsigned long addr) { unsigned long taddr = htlbpage_to_page(addr); @@ -67,23 +67,6 @@ huge_pte_offset (struct mm_struct *mm, unsigned long addr) #define mk_pte_huge(entry) { pte_val(entry) |= _PAGE_P; } -static void -set_huge_pte (struct mm_struct *mm, struct vm_area_struct *vma, - struct page *page, pte_t * page_table, int write_access) -{ - pte_t entry; - - add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE); - if (write_access) { - entry = - pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - } else - entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot)); - entry = pte_mkyoung(entry); - mk_pte_huge(entry); - set_pte(page_table, entry); - return; -} /* * This function checks for proper alignment of input addr and len parameters. */ @@ -99,68 +82,6 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len) return 0; } -int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, - struct vm_area_struct *vma) -{ - pte_t *src_pte, *dst_pte, entry; - struct page *ptepage; - unsigned long addr = vma->vm_start; - unsigned long end = vma->vm_end; - - while (addr < end) { - dst_pte = huge_pte_alloc(dst, addr); - if (!dst_pte) - goto nomem; - src_pte = huge_pte_offset(src, addr); - entry = *src_pte; - ptepage = pte_page(entry); - get_page(ptepage); - set_pte(dst_pte, entry); - add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); - addr += HPAGE_SIZE; - } - return 0; -nomem: - return -ENOMEM; -} - -int -follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, - struct page **pages, struct vm_area_struct **vmas, - unsigned long *st, int *length, int i) -{ - pte_t *ptep, pte; - unsigned long start = *st; - unsigned long pstart; - int len = *length; - struct page *page; - - do { - pstart = start & HPAGE_MASK; - ptep = huge_pte_offset(mm, start); - pte = *ptep; - -back1: - page = pte_page(pte); - if (pages) { - page += ((start & ~HPAGE_MASK) >> PAGE_SHIFT); - get_page(page); - pages[i] = page; - } - if (vmas) - vmas[i] = vma; - i++; - len--; - start += PAGE_SIZE; - if (((start & HPAGE_MASK) == pstart) && len && - (start < vma->vm_end)) - goto back1; - } while (len && start < vma->vm_end); - *length = len; - *st = start; - return i; -} - struct page *follow_huge_addr(struct mm_struct *mm, unsigned long addr, int write) { struct page *page; @@ -212,81 +133,6 @@ void hugetlb_free_pgd_range(struct mmu_gather **tlb, free_pgd_range(tlb, addr, end, floor, ceiling); } -void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long address; - pte_t *pte; - struct page *page; - - BUG_ON(start & (HPAGE_SIZE - 1)); - BUG_ON(end & (HPAGE_SIZE - 1)); - - for (address = start; address < end; address += HPAGE_SIZE) { - pte = huge_pte_offset(mm, address); - if (pte_none(*pte)) - continue; - page = pte_page(*pte); - put_page(page); - pte_clear(mm, address, pte); - } - add_mm_counter(mm, rss, - ((end - start) >> PAGE_SHIFT)); - flush_tlb_range(vma, start, end); -} - -int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) -{ - struct mm_struct *mm = current->mm; - unsigned long addr; - int ret = 0; - - BUG_ON(vma->vm_start & ~HPAGE_MASK); - BUG_ON(vma->vm_end & ~HPAGE_MASK); - - spin_lock(&mm->page_table_lock); - for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { - unsigned long idx; - pte_t *pte = huge_pte_alloc(mm, addr); - struct page *page; - - if (!pte) { - ret = -ENOMEM; - goto out; - } - if (!pte_none(*pte)) - continue; - - idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) - + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); - page = find_get_page(mapping, idx); - if (!page) { - /* charge the fs quota first */ - if (hugetlb_get_quota(mapping)) { - ret = -ENOMEM; - goto out; - } - page = alloc_huge_page(); - if (!page) { - hugetlb_put_quota(mapping); - ret = -ENOMEM; - goto out; - } - ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC); - if (! ret) { - unlock_page(page); - } else { - hugetlb_put_quota(mapping); - page_cache_release(page); - goto out; - } - } - set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); - } -out: - spin_unlock(&mm->page_table_lock); - return ret; -} - unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c index d3bf86a..b4ab766 100644 --- a/arch/ppc64/mm/hugetlbpage.c +++ b/arch/ppc64/mm/hugetlbpage.c @@ -121,7 +121,7 @@ static pte_t *hugepte_alloc(struct mm_struct *mm, pud_t *dir, unsigned long addr return hugepte_offset(dir, addr); } -static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) +pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) { pud_t *pud; @@ -134,7 +134,7 @@ static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) return hugepte_offset(pud, addr); } -static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) +pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) { pud_t *pud; @@ -147,25 +147,6 @@ static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) return hugepte_alloc(mm, pud, addr); } -static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long addr, struct page *page, - pte_t *ptep, int write_access) -{ - pte_t entry; - - add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE); - if (write_access) { - entry = - pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - } else { - entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot)); - } - entry = pte_mkyoung(entry); - entry = pte_mkhuge(entry); - - set_pte_at(mm, addr, ptep, entry); -} - /* * This function checks for proper alignment of input addr and len parameters. */ @@ -259,80 +240,6 @@ int prepare_hugepage_range(unsigned long addr, unsigned long len) return -EINVAL; } -int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, - struct vm_area_struct *vma) -{ - pte_t *src_pte, *dst_pte, entry; - struct page *ptepage; - unsigned long addr = vma->vm_start; - unsigned long end = vma->vm_end; - int err = -ENOMEM; - - while (addr < end) { - dst_pte = huge_pte_alloc(dst, addr); - if (!dst_pte) - goto out; - - src_pte = huge_pte_offset(src, addr); - entry = *src_pte; - - ptepage = pte_page(entry); - get_page(ptepage); - add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); - set_pte_at(dst, addr, dst_pte, entry); - - addr += HPAGE_SIZE; - } - - err = 0; - out: - return err; -} - -int -follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, - struct page **pages, struct vm_area_struct **vmas, - unsigned long *position, int *length, int i) -{ - unsigned long vpfn, vaddr = *position; - int remainder = *length; - - WARN_ON(!is_vm_hugetlb_page(vma)); - - vpfn = vaddr/PAGE_SIZE; - while (vaddr < vma->vm_end && remainder) { - if (pages) { - pte_t *pte; - struct page *page; - - pte = huge_pte_offset(mm, vaddr); - - /* hugetlb should be locked, and hence, prefaulted */ - WARN_ON(!pte || pte_none(*pte)); - - page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)]; - - WARN_ON(!PageCompound(page)); - - get_page(page); - pages[i] = page; - } - - if (vmas) - vmas[i] = vma; - - vaddr += PAGE_SIZE; - ++vpfn; - --remainder; - ++i; - } - - *length = remainder; - *position = vaddr; - - return i; -} - struct page * follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) { @@ -363,89 +270,6 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address, return NULL; } -void unmap_hugepage_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long addr; - pte_t *ptep; - struct page *page; - - WARN_ON(!is_vm_hugetlb_page(vma)); - BUG_ON((start % HPAGE_SIZE) != 0); - BUG_ON((end % HPAGE_SIZE) != 0); - - for (addr = start; addr < end; addr += HPAGE_SIZE) { - pte_t pte; - - ptep = huge_pte_offset(mm, addr); - if (!ptep || pte_none(*ptep)) - continue; - - pte = *ptep; - page = pte_page(pte); - pte_clear(mm, addr, ptep); - - put_page(page); - } - add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT)); - flush_tlb_pending(); -} - -int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) -{ - struct mm_struct *mm = current->mm; - unsigned long addr; - int ret = 0; - - WARN_ON(!is_vm_hugetlb_page(vma)); - BUG_ON((vma->vm_start % HPAGE_SIZE) != 0); - BUG_ON((vma->vm_end % HPAGE_SIZE) != 0); - - spin_lock(&mm->page_table_lock); - for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { - unsigned long idx; - pte_t *pte = huge_pte_alloc(mm, addr); - struct page *page; - - if (!pte) { - ret = -ENOMEM; - goto out; - } - if (! pte_none(*pte)) - continue; - - idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) - + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); - page = find_get_page(mapping, idx); - if (!page) { - /* charge the fs quota first */ - if (hugetlb_get_quota(mapping)) { - ret = -ENOMEM; - goto out; - } - page = alloc_huge_page(); - if (!page) { - hugetlb_put_quota(mapping); - ret = -ENOMEM; - goto out; - } - ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC); - if (! ret) { - unlock_page(page); - } else { - hugetlb_put_quota(mapping); - free_huge_page(page); - goto out; - } - } - set_huge_pte(mm, vma, addr, page, pte, vma->vm_flags & VM_WRITE); - } -out: - spin_unlock(&mm->page_table_lock); - return ret; -} - /* Because we have an exclusive hugepage region which lies within the * normal user address space, we have to take special measures to make * non-huge mmap()s evade the hugepage reserved regions. */ diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c index 1f897ba..95bb1a6 100644 --- a/arch/sh/mm/hugetlbpage.c +++ b/arch/sh/mm/hugetlbpage.c @@ -24,7 +24,7 @@ #include #include -static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) +pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; pmd_t *pmd; @@ -39,7 +39,7 @@ static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) return pte; } -static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) +pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; pmd_t *pmd; @@ -56,28 +56,34 @@ static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) #define mk_pte_huge(entry) do { pte_val(entry) |= _PAGE_SZHUGE; } while (0) -static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, - struct page *page, pte_t * page_table, int write_access) +void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t entry) { - unsigned long i; - pte_t entry; + int i; - add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE); + for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { + set_pte_at(mm, addr, ptep, entry); + ptep++; + addr += PAGE_SIZE; + pte_val(entry) += PAGE_SIZE; + } +} - if (write_access) - entry = pte_mkwrite(pte_mkdirty(mk_pte(page, - vma->vm_page_prot))); - else - entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot)); - entry = pte_mkyoung(entry); - mk_pte_huge(entry); +pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, + pte_t *ptep) +{ + pte_t entry; + int i; - for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { - set_pte(page_table, entry); - page_table++; + entry = *ptep; - pte_val(entry) += PAGE_SIZE; + for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { + pte_clear(mm, addr, ptep); + addr += PAGE_SIZE; + ptep++; } + + return entry; } /* @@ -92,79 +98,6 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len) return 0; } -int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, - struct vm_area_struct *vma) -{ - pte_t *src_pte, *dst_pte, entry; - struct page *ptepage; - unsigned long addr = vma->vm_start; - unsigned long end = vma->vm_end; - int i; - - while (addr < end) { - dst_pte = huge_pte_alloc(dst, addr); - if (!dst_pte) - goto nomem; - src_pte = huge_pte_offset(src, addr); - BUG_ON(!src_pte || pte_none(*src_pte)); - entry = *src_pte; - ptepage = pte_page(entry); - get_page(ptepage); - for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { - set_pte(dst_pte, entry); - pte_val(entry) += PAGE_SIZE; - dst_pte++; - } - add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); - addr += HPAGE_SIZE; - } - return 0; - -nomem: - return -ENOMEM; -} - -int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, - struct page **pages, struct vm_area_struct **vmas, - unsigned long *position, int *length, int i) -{ - unsigned long vaddr = *position; - int remainder = *length; - - WARN_ON(!is_vm_hugetlb_page(vma)); - - while (vaddr < vma->vm_end && remainder) { - if (pages) { - pte_t *pte; - struct page *page; - - pte = huge_pte_offset(mm, vaddr); - - /* hugetlb should be locked, and hence, prefaulted */ - BUG_ON(!pte || pte_none(*pte)); - - page = pte_page(*pte); - - WARN_ON(!PageCompound(page)); - - get_page(page); - pages[i] = page; - } - - if (vmas) - vmas[i] = vma; - - vaddr += PAGE_SIZE; - --remainder; - ++i; - } - - *length = remainder; - *position = vaddr; - - return i; -} - struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) { @@ -181,84 +114,3 @@ struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, { return NULL; } - -void unmap_hugepage_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long address; - pte_t *pte; - struct page *page; - int i; - - BUG_ON(start & (HPAGE_SIZE - 1)); - BUG_ON(end & (HPAGE_SIZE - 1)); - - for (address = start; address < end; address += HPAGE_SIZE) { - pte = huge_pte_offset(mm, address); - BUG_ON(!pte); - if (pte_none(*pte)) - continue; - page = pte_page(*pte); - put_page(page); - for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { - pte_clear(mm, address+(i*PAGE_SIZE), pte); - pte++; - } - } - add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT)); - flush_tlb_range(vma, start, end); -} - -int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) -{ - struct mm_struct *mm = current->mm; - unsigned long addr; - int ret = 0; - - BUG_ON(vma->vm_start & ~HPAGE_MASK); - BUG_ON(vma->vm_end & ~HPAGE_MASK); - - spin_lock(&mm->page_table_lock); - for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { - unsigned long idx; - pte_t *pte = huge_pte_alloc(mm, addr); - struct page *page; - - if (!pte) { - ret = -ENOMEM; - goto out; - } - if (!pte_none(*pte)) - continue; - - idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) - + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); - page = find_get_page(mapping, idx); - if (!page) { - /* charge the fs quota first */ - if (hugetlb_get_quota(mapping)) { - ret = -ENOMEM; - goto out; - } - page = alloc_huge_page(); - if (!page) { - hugetlb_put_quota(mapping); - ret = -ENOMEM; - goto out; - } - ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC); - if (! ret) { - unlock_page(page); - } else { - hugetlb_put_quota(mapping); - free_huge_page(page); - goto out; - } - } - set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); - } -out: - spin_unlock(&mm->page_table_lock); - return ret; -} diff --git a/arch/sh64/mm/hugetlbpage.c b/arch/sh64/mm/hugetlbpage.c index bcad2ae..dcd9c8a 100644 --- a/arch/sh64/mm/hugetlbpage.c +++ b/arch/sh64/mm/hugetlbpage.c @@ -24,7 +24,7 @@ #include #include -static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) +pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; pmd_t *pmd; @@ -39,7 +39,7 @@ static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) return pte; } -static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) +pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; pmd_t *pmd; @@ -80,6 +80,20 @@ static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, } } +pte_t huge_ptep_get_and_clear(pte_t *ptep) +{ + pte_t entry; + + entry = *ptep; + + for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { + pte_clear(pte); + pte++; + } + + return entry; +} + /* * This function checks for proper alignment of input addr and len parameters. */ diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c index 5a1f831..625cbb3 100644 --- a/arch/sparc64/mm/hugetlbpage.c +++ b/arch/sparc64/mm/hugetlbpage.c @@ -22,7 +22,7 @@ #include #include -static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) +pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; pud_t *pud; @@ -41,7 +41,7 @@ static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) return pte; } -static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) +pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; pud_t *pud; @@ -62,30 +62,34 @@ static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) #define mk_pte_huge(entry) do { pte_val(entry) |= _PAGE_SZHUGE; } while (0) -static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long addr, - struct page *page, pte_t * page_table, int write_access) +void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t entry) { - unsigned long i; - pte_t entry; + int i; + + for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { + set_pte_at(mm, addr, ptep, entry); + ptep++; + addr += PAGE_SIZE; + pte_val(entry) += PAGE_SIZE; + } +} - add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE); +pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, + pte_t *ptep) +{ + pte_t entry; + int i; - if (write_access) - entry = pte_mkwrite(pte_mkdirty(mk_pte(page, - vma->vm_page_prot))); - else - entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot)); - entry = pte_mkyoung(entry); - mk_pte_huge(entry); + entry = *ptep; for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { - set_pte_at(mm, addr, page_table, entry); - page_table++; + pte_clear(mm, addr, ptep); addr += PAGE_SIZE; - - pte_val(entry) += PAGE_SIZE; + ptep++; } + + return entry; } /* @@ -100,79 +104,6 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len) return 0; } -int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, - struct vm_area_struct *vma) -{ - pte_t *src_pte, *dst_pte, entry; - struct page *ptepage; - unsigned long addr = vma->vm_start; - unsigned long end = vma->vm_end; - int i; - - while (addr < end) { - dst_pte = huge_pte_alloc(dst, addr); - if (!dst_pte) - goto nomem; - src_pte = huge_pte_offset(src, addr); - BUG_ON(!src_pte || pte_none(*src_pte)); - entry = *src_pte; - ptepage = pte_page(entry); - get_page(ptepage); - for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { - set_pte_at(dst, addr, dst_pte, entry); - pte_val(entry) += PAGE_SIZE; - dst_pte++; - addr += PAGE_SIZE; - } - add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); - } - return 0; - -nomem: - return -ENOMEM; -} - -int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, - struct page **pages, struct vm_area_struct **vmas, - unsigned long *position, int *length, int i) -{ - unsigned long vaddr = *position; - int remainder = *length; - - WARN_ON(!is_vm_hugetlb_page(vma)); - - while (vaddr < vma->vm_end && remainder) { - if (pages) { - pte_t *pte; - struct page *page; - - pte = huge_pte_offset(mm, vaddr); - - /* hugetlb should be locked, and hence, prefaulted */ - BUG_ON(!pte || pte_none(*pte)); - - page = pte_page(*pte); - - WARN_ON(!PageCompound(page)); - - get_page(page); - pages[i] = page; - } - - if (vmas) - vmas[i] = vma; - - vaddr += PAGE_SIZE; - --remainder; - ++i; - } - - *length = remainder; - *position = vaddr; - - return i; -} - struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) { @@ -190,34 +121,6 @@ struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, return NULL; } -void unmap_hugepage_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long address; - pte_t *pte; - struct page *page; - int i; - - BUG_ON(start & (HPAGE_SIZE - 1)); - BUG_ON(end & (HPAGE_SIZE - 1)); - - for (address = start; address < end; address += HPAGE_SIZE) { - pte = huge_pte_offset(mm, address); - BUG_ON(!pte); - if (pte_none(*pte)) - continue; - page = pte_page(*pte); - put_page(page); - for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { - pte_clear(mm, address+(i*PAGE_SIZE), pte); - pte++; - } - } - add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT)); - flush_tlb_range(vma, start, end); -} - static void context_reload(void *__data) { struct mm_struct *mm = __data; @@ -226,12 +129,8 @@ static void context_reload(void *__data) load_secondary_context(mm); } -int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) +void hugetlb_prefault_arch_hook(struct mm_struct *mm) { - struct mm_struct *mm = current->mm; - unsigned long addr; - int ret = 0; - /* On UltraSPARC-III+ and later, configure the second half of * the Data-TLB for huge pages. */ @@ -261,50 +160,4 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) } spin_unlock(&ctx_alloc_lock); } - - BUG_ON(vma->vm_start & ~HPAGE_MASK); - BUG_ON(vma->vm_end & ~HPAGE_MASK); - - spin_lock(&mm->page_table_lock); - for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { - unsigned long idx; - pte_t *pte = huge_pte_alloc(mm, addr); - struct page *page; - - if (!pte) { - ret = -ENOMEM; - goto out; - } - if (!pte_none(*pte)) - continue; - - idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) - + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); - page = find_get_page(mapping, idx); - if (!page) { - /* charge the fs quota first */ - if (hugetlb_get_quota(mapping)) { - ret = -ENOMEM; - goto out; - } - page = alloc_huge_page(); - if (!page) { - hugetlb_put_quota(mapping); - ret = -ENOMEM; - goto out; - } - ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC); - if (! ret) { - unlock_page(page); - } else { - hugetlb_put_quota(mapping); - free_huge_page(page); - goto out; - } - } - set_huge_pte(mm, vma, addr, page, pte, vma->vm_flags & VM_WRITE); - } -out: - spin_unlock(&mm->page_table_lock); - return ret; } diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h index ed13969..41400d3 100644 --- a/include/asm-i386/page.h +++ b/include/asm-i386/page.h @@ -68,6 +68,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define HPAGE_MASK (~(HPAGE_SIZE - 1)) #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA +#define ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE #endif #define pgd_val(x) ((x).pgd) diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 8d60c2b..e9efe14 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -236,6 +236,7 @@ static inline pte_t pte_mkexec(pte_t pte) { (pte).pte_low |= _PAGE_USER; return static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; } static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; } static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; } +static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PRESENT | _PAGE_PSE; return pte; } #ifdef CONFIG_X86_PAE # include @@ -275,7 +276,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, */ #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) -#define mk_pte_huge(entry) ((entry).pte_low |= _PAGE_PRESENT | _PAGE_PSE) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h index fcc9c33..48586e0 100644 --- a/include/asm-ia64/pgtable.h +++ b/include/asm-ia64/pgtable.h @@ -283,6 +283,7 @@ ia64_phys_addr_valid (unsigned long addr) #define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_A)) #define pte_mkclean(pte) (__pte(pte_val(pte) & ~_PAGE_D)) #define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_D)) +#define pte_mkhuge(pte) (__pte(pte_val(pte) | _PAGE_P)) /* * Macro to a page protection value as "uncacheable". Note that "protection" is really a diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index 4c6d129..180467b 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -31,6 +31,7 @@ #define HPAGE_SIZE (1UL << HPAGE_SHIFT) #define HPAGE_MASK (~(HPAGE_SIZE-1)) #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT) +#define ARCH_HAS_SETCLEAR_HUGE_PTE #endif #ifdef __KERNEL__ diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index cd847a4..ecb9095 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h @@ -196,6 +196,7 @@ static inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _ static inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; } static inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; } static inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; } +static inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; } /* * Macro and implementation to make a page protection as uncachable. diff --git a/include/asm-sh64/page.h b/include/asm-sh64/page.h index e1f7f5a..d6167f1 100644 --- a/include/asm-sh64/page.h +++ b/include/asm-sh64/page.h @@ -41,6 +41,7 @@ #define HPAGE_SIZE (1UL << HPAGE_SHIFT) #define HPAGE_MASK (~(HPAGE_SIZE-1)) #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT) +#define ARCH_HAS_SETCLEAR_HUGE_PTE #endif #ifdef __KERNEL__ diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h index 525e152..78ac6be 100644 --- a/include/asm-sh64/pgtable.h +++ b/include/asm-sh64/pgtable.h @@ -430,6 +430,8 @@ extern inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | extern inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_EXECUTE)); return pte; } extern inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; } extern inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; } +extern inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; } + /* * Conversion functions: convert a page and protection to a page entry. diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h index 219ea04..b87dbbd 100644 --- a/include/asm-sparc64/page.h +++ b/include/asm-sparc64/page.h @@ -95,6 +95,8 @@ typedef unsigned long pgprot_t; #define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT) #define HPAGE_MASK (~(HPAGE_SIZE - 1UL)) #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) +#define ARCH_HAS_SETCLEAR_HUGE_PTE +#define ARCH_HAS_HUGETLB_PREFAULT_HOOK #endif #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_32BIT) ? \ diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index ae2cd5b..1ae00c5 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -286,6 +286,7 @@ static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot) #define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_ACCESSED | _PAGE_R)) #define pte_mkwrite(pte) (__pte(pte_val(pte) | _PAGE_WRITE)) #define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_MODIFIED | _PAGE_W)) +#define pte_mkhuge(pte) (__pte(pte_val(pte) | _PAGE_SZHUGE)) /* to find an entry in a page-table-directory. */ #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h index f430480..9ce338c 100644 --- a/include/asm-x86_64/page.h +++ b/include/asm-x86_64/page.h @@ -28,6 +28,7 @@ #define HPAGE_SIZE ((1UL) << HPAGE_SHIFT) #define HPAGE_MASK (~(HPAGE_SIZE - 1)) #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) +#define ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE #ifdef __KERNEL__ #ifndef __ASSEMBLY__ diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h index db2a0ef..4eec176 100644 --- a/include/asm-x86_64/pgtable.h +++ b/include/asm-x86_64/pgtable.h @@ -253,6 +253,7 @@ extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; } static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } +#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT) extern inline pte_t pte_rdprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; } extern inline pte_t pte_exprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; } extern inline pte_t pte_mkclean(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; } @@ -263,6 +264,7 @@ extern inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _ extern inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; } extern inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; } extern inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; } +extern inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | __LARGE_PTE)); return pte; } struct vm_area_struct; @@ -290,7 +292,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, */ #define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT)) -#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT) static inline int pmd_large(pmd_t pte) { return (pmd_val(pte) & __LARGE_PTE) == __LARGE_PTE; } diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 6af1ae4..f529d14 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -4,6 +4,7 @@ #ifdef CONFIG_HUGETLB_PAGE #include +#include struct ctl_table; @@ -22,12 +23,6 @@ int hugetlb_report_meminfo(char *); int hugetlb_report_node_meminfo(int, char *); int is_hugepage_mem_enough(size_t); unsigned long hugetlb_total_pages(void); -struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, - int write); -struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, - pmd_t *pmd, int write); -int is_aligned_hugepage_range(unsigned long addr, unsigned long len); -int pmd_huge(pmd_t pmd); struct page *alloc_huge_page(void); void free_huge_page(struct page *); @@ -35,6 +30,17 @@ extern unsigned long max_huge_pages; extern const unsigned long hugetlb_zero, hugetlb_infinity; extern int sysctl_hugetlb_shm_group; +/* arch callbacks */ + +pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr); +pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr); +struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, + int write); +struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, + pmd_t *pmd, int write); +int is_aligned_hugepage_range(unsigned long addr, unsigned long len); +int pmd_huge(pmd_t pmd); + #ifndef ARCH_HAS_HUGEPAGE_ONLY_RANGE #define is_hugepage_only_range(mm, addr, len) 0 #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \ @@ -48,6 +54,28 @@ extern int sysctl_hugetlb_shm_group; int prepare_hugepage_range(unsigned long addr, unsigned long len); #endif +#ifndef ARCH_HAS_SETCLEAR_HUGE_PTE +#define set_huge_pte_at(mm, addr, ptep, pte) set_pte_at(mm, addr, ptep, pte) +#define huge_ptep_get_and_clear(mm, addr, ptep) ptep_get_and_clear(mm, addr, ptep) +#else +void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte); +pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, + pte_t *ptep); +#endif + +#ifndef ARCH_HAS_HUGETLB_PREFAULT_HOOK +#define hugetlb_prefault_arch_hook(mm) do { } while (0) +#else +void hugetlb_prefault_arch_hook(struct mm_struct *mm); +#endif + +#ifndef ARCH_HAS_HUGETLB_CLEAN_STALE_PGTABLE +#define hugetlb_clean_stale_pgtable(pte) BUG() +#else +void hugetlb_clean_stale_pgtable(pte_t *pte); +#endif + #else /* !CONFIG_HUGETLB_PAGE */ static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 4eb5ae3..fbd1111 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -7,10 +7,14 @@ #include #include #include -#include #include #include #include +#include +#include +#include + +#include const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL; static unsigned long nr_huge_pages, free_huge_pages; @@ -249,6 +253,72 @@ struct vm_operations_struct hugetlb_vm_ops = { .nopage = hugetlb_nopage, }; +static pte_t make_huge_pte(struct vm_area_struct *vma, struct page *page) +{ + pte_t entry; + + if (vma->vm_flags & VM_WRITE) { + entry = + pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + } else { + entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot)); + } + entry = pte_mkyoung(entry); + entry = pte_mkhuge(entry); + + return entry; +} + +int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, + struct vm_area_struct *vma) +{ + pte_t *src_pte, *dst_pte, entry; + struct page *ptepage; + unsigned long addr = vma->vm_start; + unsigned long end = vma->vm_end; + + while (addr < end) { + dst_pte = huge_pte_alloc(dst, addr); + if (!dst_pte) + goto nomem; + src_pte = huge_pte_offset(src, addr); + BUG_ON(!src_pte || pte_none(*src_pte)); /* prefaulted */ + entry = *src_pte; + ptepage = pte_page(entry); + get_page(ptepage); + add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); + set_huge_pte_at(dst, addr, dst_pte, entry); + addr += HPAGE_SIZE; + } + return 0; + +nomem: + return -ENOMEM; +} + +void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long address; + pte_t pte; + struct page *page; + + WARN_ON(!is_vm_hugetlb_page(vma)); + BUG_ON(start & ~HPAGE_MASK); + BUG_ON(end & ~HPAGE_MASK); + + for (address = start; address < end; address += HPAGE_SIZE) { + pte = huge_ptep_get_and_clear(mm, address, huge_pte_offset(mm, address)); + if (pte_none(pte)) + continue; + page = pte_page(pte); + put_page(page); + } + add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT)); + flush_tlb_range(vma, start, end); +} + void zap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long length) { @@ -258,3 +328,108 @@ void zap_hugepage_range(struct vm_area_struct *vma, unmap_hugepage_range(vma, start, start + length); spin_unlock(&mm->page_table_lock); } + +int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) +{ + struct mm_struct *mm = current->mm; + unsigned long addr; + int ret = 0; + + WARN_ON(!is_vm_hugetlb_page(vma)); + BUG_ON(vma->vm_start & ~HPAGE_MASK); + BUG_ON(vma->vm_end & ~HPAGE_MASK); + + hugetlb_prefault_arch_hook(mm); + + spin_lock(&mm->page_table_lock); + for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { + unsigned long idx; + pte_t *pte = huge_pte_alloc(mm, addr); + struct page *page; + + if (!pte) { + ret = -ENOMEM; + goto out; + } + if (! pte_none(*pte)) + hugetlb_clean_stale_pgtable(pte); + + idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) + + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); + page = find_get_page(mapping, idx); + if (!page) { + /* charge the fs quota first */ + if (hugetlb_get_quota(mapping)) { + ret = -ENOMEM; + goto out; + } + page = alloc_huge_page(); + if (!page) { + hugetlb_put_quota(mapping); + ret = -ENOMEM; + goto out; + } + ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC); + if (! ret) { + unlock_page(page); + } else { + hugetlb_put_quota(mapping); + free_huge_page(page); + goto out; + } + } + add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE); + set_huge_pte_at(mm, addr, pte, make_huge_pte(vma, page)); + } +out: + spin_unlock(&mm->page_table_lock); + return ret; +} + +int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, + struct page **pages, struct vm_area_struct **vmas, + unsigned long *position, int *length, int i) +{ + unsigned long vpfn, vaddr = *position; + int remainder = *length; + + BUG_ON(!is_vm_hugetlb_page(vma)); + + vpfn = vaddr/PAGE_SIZE; + while (vaddr < vma->vm_end && remainder) { + + if (pages) { + pte_t *pte; + struct page *page; + + /* Some archs (sparc64, sh*) have multiple + * pte_ts to each hugepage. We have to make + * sure we get the first, for the page + * indexing below to work. */ + pte = huge_pte_offset(mm, vaddr & HPAGE_MASK); + + /* hugetlb should be locked, and hence, prefaulted */ + WARN_ON(!pte || pte_none(*pte)); + + page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)]; + + WARN_ON(!PageCompound(page)); + + get_page(page); + pages[i] = page; + } + + if (vmas) + vmas[i] = vma; + + vaddr += PAGE_SIZE; + ++vpfn; + --remainder; + ++i; + } + + *length = remainder; + *position = vaddr; + + return i; +} -- cgit v0.10.2 From e7c8d5c9955a4d2e88e36b640563f5d6d5aba48a Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Tue, 21 Jun 2005 17:14:47 -0700 Subject: [PATCH] node local per-cpu-pages This patch modifies the way pagesets in struct zone are managed. Each zone has a per-cpu array of pagesets. So any particular CPU has some memory in each zone structure which belongs to itself. Even if that CPU is not local to that zone. So the patch relocates the pagesets for each cpu to the node that is nearest to the cpu instead of allocating the pagesets in the (possibly remote) target zone. This means that the operations to manage pages on remote zone can be done with information available locally. We play a macro trick so that non-NUMA pmachines avoid the additional pointer chase on the page allocator fastpath. AIM7 benchmark on a 32 CPU SGI Altix w/o patches: Tasks jobs/min jti jobs/min/task real cpu 1 484.68 100 484.6769 12.01 1.97 Fri Mar 25 11:01:42 2005 100 27140.46 89 271.4046 21.44 148.71 Fri Mar 25 11:02:04 2005 200 30792.02 82 153.9601 37.80 296.72 Fri Mar 25 11:02:42 2005 300 32209.27 81 107.3642 54.21 451.34 Fri Mar 25 11:03:37 2005 400 34962.83 78 87.4071 66.59 588.97 Fri Mar 25 11:04:44 2005 500 31676.92 75 63.3538 91.87 742.71 Fri Mar 25 11:06:16 2005 600 36032.69 73 60.0545 96.91 885.44 Fri Mar 25 11:07:54 2005 700 35540.43 77 50.7720 114.63 1024.28 Fri Mar 25 11:09:49 2005 800 33906.70 74 42.3834 137.32 1181.65 Fri Mar 25 11:12:06 2005 900 34120.67 73 37.9119 153.51 1325.26 Fri Mar 25 11:14:41 2005 1000 34802.37 74 34.8024 167.23 1465.26 Fri Mar 25 11:17:28 2005 with slab API changes and pageset patch: Tasks jobs/min jti jobs/min/task real cpu 1 485.00 100 485.0000 12.00 1.96 Fri Mar 25 11:46:18 2005 100 28000.96 89 280.0096 20.79 150.45 Fri Mar 25 11:46:39 2005 200 32285.80 79 161.4290 36.05 293.37 Fri Mar 25 11:47:16 2005 300 40424.15 84 134.7472 43.19 438.42 Fri Mar 25 11:47:59 2005 400 39155.01 79 97.8875 59.46 590.05 Fri Mar 25 11:48:59 2005 500 37881.25 82 75.7625 76.82 730.19 Fri Mar 25 11:50:16 2005 600 39083.14 78 65.1386 89.35 872.79 Fri Mar 25 11:51:46 2005 700 38627.83 77 55.1826 105.47 1022.46 Fri Mar 25 11:53:32 2005 800 39631.94 78 49.5399 117.48 1169.94 Fri Mar 25 11:55:30 2005 900 36903.70 79 41.0041 141.94 1310.78 Fri Mar 25 11:57:53 2005 1000 36201.23 77 36.2012 160.77 1458.31 Fri Mar 25 12:00:34 2005 Signed-off-by: Christoph Lameter Signed-off-by: Shobhit Dayal Signed-off-by: Shai Fultheim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/base/node.c b/drivers/base/node.c index 5d4517c..904b27c 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -87,7 +87,7 @@ static ssize_t node_read_numastat(struct sys_device * dev, char * buf) for (i = 0; i < MAX_NR_ZONES; i++) { struct zone *z = &pg->node_zones[i]; for (cpu = 0; cpu < NR_CPUS; cpu++) { - struct per_cpu_pageset *ps = &z->pageset[cpu]; + struct per_cpu_pageset *ps = zone_pcp(z,cpu); numa_hit += ps->numa_hit; numa_miss += ps->numa_miss; numa_foreign += ps->numa_foreign; diff --git a/include/linux/mm.h b/include/linux/mm.h index 17518fe..1813b16 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -691,6 +691,12 @@ extern void show_mem(void); extern void si_meminfo(struct sysinfo * val); extern void si_meminfo_node(struct sysinfo *val, int nid); +#ifdef CONFIG_NUMA +extern void setup_per_cpu_pageset(void); +#else +static inline void setup_per_cpu_pageset(void) {} +#endif + /* prio_tree.c */ void vma_prio_tree_add(struct vm_area_struct *, struct vm_area_struct *old); void vma_prio_tree_insert(struct vm_area_struct *, struct prio_tree_root *); diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 18fed8b..4733d35 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -63,6 +63,12 @@ struct per_cpu_pageset { #endif } ____cacheline_aligned_in_smp; +#ifdef CONFIG_NUMA +#define zone_pcp(__z, __cpu) ((__z)->pageset[(__cpu)]) +#else +#define zone_pcp(__z, __cpu) (&(__z)->pageset[(__cpu)]) +#endif + #define ZONE_DMA 0 #define ZONE_NORMAL 1 #define ZONE_HIGHMEM 2 @@ -122,8 +128,11 @@ struct zone { */ unsigned long lowmem_reserve[MAX_NR_ZONES]; +#ifdef CONFIG_NUMA + struct per_cpu_pageset *pageset[NR_CPUS]; +#else struct per_cpu_pageset pageset[NR_CPUS]; - +#endif /* * free areas of different sizes */ diff --git a/init/main.c b/init/main.c index 40bf367..d324801 100644 --- a/init/main.c +++ b/init/main.c @@ -490,6 +490,7 @@ asmlinkage void __init start_kernel(void) vfs_caches_init_early(); mem_init(); kmem_cache_init(); + setup_per_cpu_pageset(); numa_policy_init(); if (late_time_init) late_time_init(); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 08c41da..39252c7 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -721,7 +721,7 @@ static struct page *alloc_page_interleave(unsigned int __nocast gfp, unsigned or zl = NODE_DATA(nid)->node_zonelists + (gfp & GFP_ZONEMASK); page = __alloc_pages(gfp, order, zl); if (page && page_zone(page) == zl->zones[0]) { - zl->zones[0]->pageset[get_cpu()].interleave_hit++; + zone_pcp(zl->zones[0],get_cpu())->interleave_hit++; put_cpu(); } return page; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 2019c1b..95cbd30 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -71,6 +71,11 @@ EXPORT_SYMBOL(nr_swap_pages); struct zone *zone_table[1 << (ZONES_SHIFT + NODES_SHIFT)]; EXPORT_SYMBOL(zone_table); +#ifdef CONFIG_NUMA +static struct per_cpu_pageset + pageset_table[MAX_NR_ZONES*MAX_NUMNODES*NR_CPUS] __initdata; +#endif + static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" }; int min_free_kbytes = 1024; @@ -520,7 +525,7 @@ static void __drain_pages(unsigned int cpu) for_each_zone(zone) { struct per_cpu_pageset *pset; - pset = &zone->pageset[cpu]; + pset = zone_pcp(zone, cpu); for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) { struct per_cpu_pages *pcp; @@ -583,12 +588,12 @@ static void zone_statistics(struct zonelist *zonelist, struct zone *z) local_irq_save(flags); cpu = smp_processor_id(); - p = &z->pageset[cpu]; + p = zone_pcp(z,cpu); if (pg == orig) { - z->pageset[cpu].numa_hit++; + p->numa_hit++; } else { p->numa_miss++; - zonelist->zones[0]->pageset[cpu].numa_foreign++; + zone_pcp(zonelist->zones[0], cpu)->numa_foreign++; } if (pg == NODE_DATA(numa_node_id())) p->local_node++; @@ -615,7 +620,7 @@ static void fastcall free_hot_cold_page(struct page *page, int cold) if (PageAnon(page)) page->mapping = NULL; free_pages_check(__FUNCTION__, page); - pcp = &zone->pageset[get_cpu()].pcp[cold]; + pcp = &zone_pcp(zone, get_cpu())->pcp[cold]; local_irq_save(flags); if (pcp->count >= pcp->high) pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0); @@ -659,7 +664,7 @@ buffered_rmqueue(struct zone *zone, int order, unsigned int __nocast gfp_flags) if (order == 0) { struct per_cpu_pages *pcp; - pcp = &zone->pageset[get_cpu()].pcp[cold]; + pcp = &zone_pcp(zone, get_cpu())->pcp[cold]; local_irq_save(flags); if (pcp->count <= pcp->low) pcp->count += rmqueue_bulk(zone, 0, @@ -1262,7 +1267,7 @@ void show_free_areas(void) if (!cpu_possible(cpu)) continue; - pageset = zone->pageset + cpu; + pageset = zone_pcp(zone, cpu); for (temperature = 0; temperature < 2; temperature++) printk("cpu %d %s: low %d, high %d, batch %d\n", @@ -1645,6 +1650,157 @@ void zone_init_free_lists(struct pglist_data *pgdat, struct zone *zone, memmap_init_zone((size), (nid), (zone), (start_pfn)) #endif +static int __devinit zone_batchsize(struct zone *zone) +{ + int batch; + + /* + * The per-cpu-pages pools are set to around 1000th of the + * size of the zone. But no more than 1/4 of a meg - there's + * no point in going beyond the size of L2 cache. + * + * OK, so we don't know how big the cache is. So guess. + */ + batch = zone->present_pages / 1024; + if (batch * PAGE_SIZE > 256 * 1024) + batch = (256 * 1024) / PAGE_SIZE; + batch /= 4; /* We effectively *= 4 below */ + if (batch < 1) + batch = 1; + + /* + * Clamp the batch to a 2^n - 1 value. Having a power + * of 2 value was found to be more likely to have + * suboptimal cache aliasing properties in some cases. + * + * For example if 2 tasks are alternately allocating + * batches of pages, one task can end up with a lot + * of pages of one half of the possible page colors + * and the other with pages of the other colors. + */ + batch = (1 << fls(batch + batch/2)) - 1; + return batch; +} + +#ifdef CONFIG_NUMA +/* + * Dynamicaly allocate memory for the + * per cpu pageset array in struct zone. + */ +static int __devinit process_zones(int cpu) +{ + struct zone *zone, *dzone; + int i; + + for_each_zone(zone) { + struct per_cpu_pageset *npageset = NULL; + + npageset = kmalloc_node(sizeof(struct per_cpu_pageset), + GFP_KERNEL, cpu_to_node(cpu)); + if (!npageset) { + zone->pageset[cpu] = NULL; + goto bad; + } + + if (zone->pageset[cpu]) { + memcpy(npageset, zone->pageset[cpu], + sizeof(struct per_cpu_pageset)); + + /* Relocate lists */ + for (i = 0; i < 2; i++) { + INIT_LIST_HEAD(&npageset->pcp[i].list); + list_splice(&zone->pageset[cpu]->pcp[i].list, + &npageset->pcp[i].list); + } + } else { + struct per_cpu_pages *pcp; + unsigned long batch; + + batch = zone_batchsize(zone); + + pcp = &npageset->pcp[0]; /* hot */ + pcp->count = 0; + pcp->low = 2 * batch; + pcp->high = 6 * batch; + pcp->batch = 1 * batch; + INIT_LIST_HEAD(&pcp->list); + + pcp = &npageset->pcp[1]; /* cold*/ + pcp->count = 0; + pcp->low = 0; + pcp->high = 2 * batch; + pcp->batch = 1 * batch; + INIT_LIST_HEAD(&pcp->list); + } + zone->pageset[cpu] = npageset; + } + + return 0; +bad: + for_each_zone(dzone) { + if (dzone == zone) + break; + kfree(dzone->pageset[cpu]); + dzone->pageset[cpu] = NULL; + } + return -ENOMEM; +} + +static inline void free_zone_pagesets(int cpu) +{ +#ifdef CONFIG_NUMA + struct zone *zone; + + for_each_zone(zone) { + struct per_cpu_pageset *pset = zone_pcp(zone, cpu); + + zone_pcp(zone, cpu) = NULL; + kfree(pset); + } +#endif +} + +static int __devinit pageset_cpuup_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + int cpu = (long)hcpu; + int ret = NOTIFY_OK; + + switch (action) { + case CPU_UP_PREPARE: + if (process_zones(cpu)) + ret = NOTIFY_BAD; + break; +#ifdef CONFIG_HOTPLUG_CPU + case CPU_DEAD: + free_zone_pagesets(cpu); + break; +#endif + default: + break; + } + return ret; +} + +static struct notifier_block pageset_notifier = + { &pageset_cpuup_callback, NULL, 0 }; + +void __init setup_per_cpu_pageset() +{ + int err; + + /* Initialize per_cpu_pageset for cpu 0. + * A cpuup callback will do this for every cpu + * as it comes online + */ + err = process_zones(smp_processor_id()); + BUG_ON(err); + register_cpu_notifier(&pageset_notifier); +} + +#endif + /* * Set up the zone data structures: * - mark all pages reserved @@ -1687,43 +1843,28 @@ static void __init free_area_init_core(struct pglist_data *pgdat, zone->temp_priority = zone->prev_priority = DEF_PRIORITY; - /* - * The per-cpu-pages pools are set to around 1000th of the - * size of the zone. But no more than 1/4 of a meg - there's - * no point in going beyond the size of L2 cache. - * - * OK, so we don't know how big the cache is. So guess. - */ - batch = zone->present_pages / 1024; - if (batch * PAGE_SIZE > 256 * 1024) - batch = (256 * 1024) / PAGE_SIZE; - batch /= 4; /* We effectively *= 4 below */ - if (batch < 1) - batch = 1; - - /* - * Clamp the batch to a 2^n - 1 value. Having a power - * of 2 value was found to be more likely to have - * suboptimal cache aliasing properties in some cases. - * - * For example if 2 tasks are alternately allocating - * batches of pages, one task can end up with a lot - * of pages of one half of the possible page colors - * and the other with pages of the other colors. - */ - batch = (1 << fls(batch + batch/2)) - 1; + batch = zone_batchsize(zone); for (cpu = 0; cpu < NR_CPUS; cpu++) { struct per_cpu_pages *pcp; +#ifdef CONFIG_NUMA + struct per_cpu_pageset *pgset; + pgset = &pageset_table[nid*MAX_NR_ZONES*NR_CPUS + + (j * NR_CPUS) + cpu]; + + zone->pageset[cpu] = pgset; +#else + struct per_cpu_pageset *pgset = zone_pcp(zone, cpu); +#endif - pcp = &zone->pageset[cpu].pcp[0]; /* hot */ + pcp = &pgset->pcp[0]; /* hot */ pcp->count = 0; pcp->low = 2 * batch; pcp->high = 6 * batch; pcp->batch = 1 * batch; INIT_LIST_HEAD(&pcp->list); - pcp = &zone->pageset[cpu].pcp[1]; /* cold */ + pcp = &pgset->pcp[1]; /* cold */ pcp->count = 0; pcp->low = 0; pcp->high = 2 * batch; @@ -1929,7 +2070,7 @@ static int zoneinfo_show(struct seq_file *m, void *arg) struct per_cpu_pageset *pageset; int j; - pageset = &zone->pageset[i]; + pageset = zone_pcp(zone, i); for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) { if (pageset->pcp[j].count) break; -- cgit v0.10.2 From 1363c3cd8603a913a27e2995dccbd70d5312d8e6 Mon Sep 17 00:00:00 2001 From: Wolfgang Wander Date: Tue, 21 Jun 2005 17:14:49 -0700 Subject: [PATCH] Avoiding mmap fragmentation Ingo recently introduced a great speedup for allocating new mmaps using the free_area_cache pointer which boosts the specweb SSL benchmark by 4-5% and causes huge performance increases in thread creation. The downside of this patch is that it does lead to fragmentation in the mmap-ed areas (visible via /proc/self/maps), such that some applications that work fine under 2.4 kernels quickly run out of memory on any 2.6 kernel. The problem is twofold: 1) the free_area_cache is used to continue a search for memory where the last search ended. Before the change new areas were always searched from the base address on. So now new small areas are cluttering holes of all sizes throughout the whole mmap-able region whereas before small holes tended to close holes near the base leaving holes far from the base large and available for larger requests. 2) the free_area_cache also is set to the location of the last munmap-ed area so in scenarios where we allocate e.g. five regions of 1K each, then free regions 4 2 3 in this order the next request for 1K will be placed in the position of the old region 3, whereas before we appended it to the still active region 1, placing it at the location of the old region 2. Before we had 1 free region of 2K, now we only get two free regions of 1K -> fragmentation. The patch addresses thes issues by introducing yet another cache descriptor cached_hole_size that contains the largest known hole size below the current free_area_cache. If a new request comes in the size is compared against the cached_hole_size and if the request can be filled with a hole below free_area_cache the search is started from the base instead. The results look promising: Whereas 2.6.12-rc4 fragments quickly and my (earlier posted) leakme.c test program terminates after 50000+ iterations with 96 distinct and fragmented maps in /proc/self/maps it performs nicely (as expected) with thread creation, Ingo's test_str02 with 20000 threads requires 0.7s system time. Taking out Ingo's patch (un-patch available per request) by basically deleting all mentions of free_area_cache from the kernel and starting the search for new memory always at the respective bases we observe: leakme terminates successfully with 11 distinctive hardly fragmented areas in /proc/self/maps but thread creating is gringdingly slow: 30+s(!) system time for Ingo's test_str02 with 20000 threads. Now - drumroll ;-) the appended patch works fine with leakme: it ends with only 7 distinct areas in /proc/self/maps and also thread creation seems sufficiently fast with 0.71s for 20000 threads. Signed-off-by: Wolfgang Wander Credit-to: "Richard Purdie" Signed-off-by: Ken Chen Acked-by: Ingo Molnar (partly) Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index 32c4b0e..3de7f84 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c @@ -73,7 +73,12 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, (!vma || addr + len <= vma->vm_start)) return addr; } - start_addr = addr = mm->free_area_cache; + if (len > mm->cached_hole_size) { + start_addr = addr = mm->free_area_cache; + } else { + start_addr = addr = TASK_UNMAPPED_BASE; + mm->cached_hole_size = 0; + } full_search: if (do_align) @@ -90,6 +95,7 @@ full_search: */ if (start_addr != TASK_UNMAPPED_BASE) { start_addr = addr = TASK_UNMAPPED_BASE; + mm->cached_hole_size = 0; goto full_search; } return -ENOMEM; @@ -101,6 +107,8 @@ full_search: mm->free_area_cache = addr + len; return addr; } + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; addr = vma->vm_end; if (do_align) addr = COLOUR_ALIGN(addr, pgoff); diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c index 5aa0600..3b099f3 100644 --- a/arch/i386/mm/hugetlbpage.c +++ b/arch/i386/mm/hugetlbpage.c @@ -140,7 +140,12 @@ static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file, struct vm_area_struct *vma; unsigned long start_addr; - start_addr = mm->free_area_cache; + if (len > mm->cached_hole_size) { + start_addr = mm->free_area_cache; + } else { + start_addr = TASK_UNMAPPED_BASE; + mm->cached_hole_size = 0; + } full_search: addr = ALIGN(start_addr, HPAGE_SIZE); @@ -154,6 +159,7 @@ full_search: */ if (start_addr != TASK_UNMAPPED_BASE) { start_addr = TASK_UNMAPPED_BASE; + mm->cached_hole_size = 0; goto full_search; } return -ENOMEM; @@ -162,6 +168,8 @@ full_search: mm->free_area_cache = addr + len; return addr; } + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; addr = ALIGN(vma->vm_end, HPAGE_SIZE); } } @@ -173,12 +181,17 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, struct mm_struct *mm = current->mm; struct vm_area_struct *vma, *prev_vma; unsigned long base = mm->mmap_base, addr = addr0; + unsigned long largest_hole = mm->cached_hole_size; int first_time = 1; /* don't allow allocations above current base */ if (mm->free_area_cache > base) mm->free_area_cache = base; + if (len <= largest_hole) { + largest_hole = 0; + mm->free_area_cache = base; + } try_again: /* make sure it can fit in the remaining address space */ if (mm->free_area_cache < len) @@ -199,13 +212,21 @@ try_again: * vma->vm_start, use it: */ if (addr + len <= vma->vm_start && - (!prev_vma || (addr >= prev_vma->vm_end))) + (!prev_vma || (addr >= prev_vma->vm_end))) { /* remember the address as a hint for next time */ - return (mm->free_area_cache = addr); - else + mm->cached_hole_size = largest_hole; + return (mm->free_area_cache = addr); + } else { /* pull free_area_cache down to the first hole */ - if (mm->free_area_cache == vma->vm_end) + if (mm->free_area_cache == vma->vm_end) { mm->free_area_cache = vma->vm_start; + mm->cached_hole_size = largest_hole; + } + } + + /* remember the largest hole we saw so far */ + if (addr + largest_hole < vma->vm_start) + largest_hole = vma->vm_start - addr; /* try just below the current vma->vm_start */ addr = (vma->vm_start - len) & HPAGE_MASK; @@ -218,6 +239,7 @@ fail: */ if (first_time) { mm->free_area_cache = base; + largest_hole = 0; first_time = 0; goto try_again; } @@ -228,6 +250,7 @@ fail: * allocations. */ mm->free_area_cache = TASK_UNMAPPED_BASE; + mm->cached_hole_size = ~0UL; addr = hugetlb_get_unmapped_area_bottomup(file, addr0, len, pgoff, flags); @@ -235,6 +258,7 @@ fail: * Restore the topdown base: */ mm->free_area_cache = base; + mm->cached_hole_size = ~0UL; return addr; } diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c index b4ab766..fdcfe97 100644 --- a/arch/ppc64/mm/hugetlbpage.c +++ b/arch/ppc64/mm/hugetlbpage.c @@ -292,7 +292,12 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, && !is_hugepage_only_range(mm, addr,len)) return addr; } - start_addr = addr = mm->free_area_cache; + if (len > mm->cached_hole_size) { + start_addr = addr = mm->free_area_cache; + } else { + start_addr = addr = TASK_UNMAPPED_BASE; + mm->cached_hole_size = 0; + } full_search: vma = find_vma(mm, addr); @@ -316,6 +321,8 @@ full_search: mm->free_area_cache = addr + len; return addr; } + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; addr = vma->vm_end; vma = vma->vm_next; } @@ -323,6 +330,7 @@ full_search: /* Make sure we didn't miss any holes */ if (start_addr != TASK_UNMAPPED_BASE) { start_addr = addr = TASK_UNMAPPED_BASE; + mm->cached_hole_size = 0; goto full_search; } return -ENOMEM; @@ -344,6 +352,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, struct vm_area_struct *vma, *prev_vma; struct mm_struct *mm = current->mm; unsigned long base = mm->mmap_base, addr = addr0; + unsigned long largest_hole = mm->cached_hole_size; int first_time = 1; /* requested length too big for entire address space */ @@ -364,6 +373,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, return addr; } + if (len <= largest_hole) { + largest_hole = 0; + mm->free_area_cache = base; + } try_again: /* make sure it can fit in the remaining address space */ if (mm->free_area_cache < len) @@ -392,13 +405,21 @@ hugepage_recheck: * vma->vm_start, use it: */ if (addr+len <= vma->vm_start && - (!prev_vma || (addr >= prev_vma->vm_end))) + (!prev_vma || (addr >= prev_vma->vm_end))) { /* remember the address as a hint for next time */ - return (mm->free_area_cache = addr); - else + mm->cached_hole_size = largest_hole; + return (mm->free_area_cache = addr); + } else { /* pull free_area_cache down to the first hole */ - if (mm->free_area_cache == vma->vm_end) + if (mm->free_area_cache == vma->vm_end) { mm->free_area_cache = vma->vm_start; + mm->cached_hole_size = largest_hole; + } + } + + /* remember the largest hole we saw so far */ + if (addr + largest_hole < vma->vm_start) + largest_hole = vma->vm_start - addr; /* try just below the current vma->vm_start */ addr = vma->vm_start-len; @@ -411,6 +432,7 @@ fail: */ if (first_time) { mm->free_area_cache = base; + largest_hole = 0; first_time = 0; goto try_again; } @@ -421,11 +443,13 @@ fail: * allocations. */ mm->free_area_cache = TASK_UNMAPPED_BASE; + mm->cached_hole_size = ~0UL; addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); /* * Restore the topdown base: */ mm->free_area_cache = base; + mm->cached_hole_size = ~0UL; return addr; } diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index df5ac29..917b2f3 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -79,6 +79,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, (!vma || addr + len <= vma->vm_start)) return addr; } + if (len <= mm->cached_hole_size) { + mm->cached_hole_size = 0; + mm->free_area_cache = TASK_UNMAPPED_BASE; + } if (flags & MAP_PRIVATE) addr = PAGE_ALIGN(mm->free_area_cache); else @@ -95,6 +99,7 @@ full_search: */ if (start_addr != TASK_UNMAPPED_BASE) { start_addr = addr = TASK_UNMAPPED_BASE; + mm->cached_hole_size = 0; goto full_search; } return -ENOMEM; @@ -106,6 +111,9 @@ full_search: mm->free_area_cache = addr + len; return addr; } + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; + addr = vma->vm_end; if (!(flags & MAP_PRIVATE)) addr = COLOUR_ALIGN(addr); diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 0077f02..5f8c822 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -84,6 +84,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi return addr; } + if (len <= mm->cached_hole_size) { + mm->cached_hole_size = 0; + mm->free_area_cache = TASK_UNMAPPED_BASE; + } start_addr = addr = mm->free_area_cache; task_size -= len; @@ -103,6 +107,7 @@ full_search: if (task_size < addr) { if (start_addr != TASK_UNMAPPED_BASE) { start_addr = addr = TASK_UNMAPPED_BASE; + mm->cached_hole_size = 0; goto full_search; } return -ENOMEM; @@ -114,6 +119,9 @@ full_search: mm->free_area_cache = addr + len; return addr; } + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; + addr = vma->vm_end; if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c index 1965efc..c12edf5 100644 --- a/arch/x86_64/ia32/ia32_aout.c +++ b/arch/x86_64/ia32/ia32_aout.c @@ -312,6 +312,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->mm->brk = ex.a_bss + (current->mm->start_brk = N_BSSADDR(ex)); current->mm->free_area_cache = TASK_UNMAPPED_BASE; + current->mm->cached_hole_size = 0; set_mm_counter(current->mm, rss, 0); current->mm->mmap = NULL; diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c index d9798dd..cc7821c 100644 --- a/arch/x86_64/kernel/sys_x86_64.c +++ b/arch/x86_64/kernel/sys_x86_64.c @@ -105,6 +105,11 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, (!vma || addr + len <= vma->vm_start)) return addr; } + if (((flags & MAP_32BIT) || test_thread_flag(TIF_IA32)) + && len <= mm->cached_hole_size) { + mm->cached_hole_size = 0; + mm->free_area_cache = begin; + } addr = mm->free_area_cache; if (addr < begin) addr = begin; @@ -120,6 +125,7 @@ full_search: */ if (start_addr != begin) { start_addr = addr = begin; + mm->cached_hole_size = 0; goto full_search; } return -ENOMEM; @@ -131,6 +137,9 @@ full_search: mm->free_area_cache = addr + len; return addr; } + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; + addr = vma->vm_end; } } diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 009b892..dd9baab 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -316,6 +316,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->mm->brk = ex.a_bss + (current->mm->start_brk = N_BSSADDR(ex)); current->mm->free_area_cache = current->mm->mmap_base; + current->mm->cached_hole_size = 0; set_mm_counter(current->mm, rss, 0); current->mm->mmap = NULL; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index f8f6b6b..7976a23 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -775,6 +775,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) change some of these later */ set_mm_counter(current->mm, rss, 0); current->mm->free_area_cache = current->mm->mmap_base; + current->mm->cached_hole_size = 0; retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), executable_stack); if (retval < 0) { diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 2af3338..3a9b6d1 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -122,6 +122,9 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, start_addr = mm->free_area_cache; + if (len <= mm->cached_hole_size) + start_addr = TASK_UNMAPPED_BASE; + full_search: addr = ALIGN(start_addr, HPAGE_SIZE); diff --git a/include/linux/sched.h b/include/linux/sched.h index 4dbb1090..b58afd9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -201,8 +201,8 @@ extern unsigned long arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags); -extern void arch_unmap_area(struct vm_area_struct *area); -extern void arch_unmap_area_topdown(struct vm_area_struct *area); +extern void arch_unmap_area(struct mm_struct *, unsigned long); +extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long); #define set_mm_counter(mm, member, value) (mm)->_##member = (value) #define get_mm_counter(mm, member) ((mm)->_##member) @@ -218,9 +218,10 @@ struct mm_struct { unsigned long (*get_unmapped_area) (struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags); - void (*unmap_area) (struct vm_area_struct *area); - unsigned long mmap_base; /* base of mmap area */ - unsigned long free_area_cache; /* first hole */ + void (*unmap_area) (struct mm_struct *mm, unsigned long addr); + unsigned long mmap_base; /* base of mmap area */ + unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */ + unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */ pgd_t * pgd; atomic_t mm_users; /* How many users with user space? */ atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ diff --git a/kernel/fork.c b/kernel/fork.c index f42a17f..876b31c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -194,6 +194,7 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) mm->mmap = NULL; mm->mmap_cache = NULL; mm->free_area_cache = oldmm->mmap_base; + mm->cached_hole_size = ~0UL; mm->map_count = 0; set_mm_counter(mm, rss, 0); set_mm_counter(mm, anon_rss, 0); @@ -322,6 +323,7 @@ static struct mm_struct * mm_init(struct mm_struct * mm) mm->ioctx_list = NULL; mm->default_kioctx = (struct kioctx)INIT_KIOCTX(mm->default_kioctx, *mm); mm->free_area_cache = TASK_UNMAPPED_BASE; + mm->cached_hole_size = ~0UL; if (likely(!mm_alloc_pgd(mm))) { mm->def_flags = 0; diff --git a/mm/mmap.c b/mm/mmap.c index de54acd..9da23c1 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1175,7 +1175,12 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, (!vma || addr + len <= vma->vm_start)) return addr; } - start_addr = addr = mm->free_area_cache; + if (len > mm->cached_hole_size) { + start_addr = addr = mm->free_area_cache; + } else { + start_addr = addr = TASK_UNMAPPED_BASE; + mm->cached_hole_size = 0; + } full_search: for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { @@ -1186,7 +1191,9 @@ full_search: * some holes. */ if (start_addr != TASK_UNMAPPED_BASE) { - start_addr = addr = TASK_UNMAPPED_BASE; + addr = TASK_UNMAPPED_BASE; + start_addr = addr; + mm->cached_hole_size = 0; goto full_search; } return -ENOMEM; @@ -1198,19 +1205,22 @@ full_search: mm->free_area_cache = addr + len; return addr; } + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; addr = vma->vm_end; } } #endif -void arch_unmap_area(struct vm_area_struct *area) +void arch_unmap_area(struct mm_struct *mm, unsigned long addr) { /* * Is this a new hole at the lowest possible address? */ - if (area->vm_start >= TASK_UNMAPPED_BASE && - area->vm_start < area->vm_mm->free_area_cache) - area->vm_mm->free_area_cache = area->vm_start; + if (addr >= TASK_UNMAPPED_BASE && addr < mm->free_area_cache) { + mm->free_area_cache = addr; + mm->cached_hole_size = ~0UL; + } } /* @@ -1240,6 +1250,12 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, return addr; } + /* check if free_area_cache is useful for us */ + if (len <= mm->cached_hole_size) { + mm->cached_hole_size = 0; + mm->free_area_cache = mm->mmap_base; + } + /* either no address requested or can't fit in requested address hole */ addr = mm->free_area_cache; @@ -1264,6 +1280,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, /* remember the address as a hint for next time */ return (mm->free_area_cache = addr); + /* remember the largest hole we saw so far */ + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; + /* try just below the current vma->vm_start */ addr = vma->vm_start-len; } while (len < vma->vm_start); @@ -1274,28 +1294,30 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, * can happen with large stack limits and large mmap() * allocations. */ - mm->free_area_cache = TASK_UNMAPPED_BASE; + mm->cached_hole_size = ~0UL; + mm->free_area_cache = TASK_UNMAPPED_BASE; addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); /* * Restore the topdown base: */ mm->free_area_cache = mm->mmap_base; + mm->cached_hole_size = ~0UL; return addr; } #endif -void arch_unmap_area_topdown(struct vm_area_struct *area) +void arch_unmap_area_topdown(struct mm_struct *mm, unsigned long addr) { /* * Is this a new hole at the highest possible address? */ - if (area->vm_end > area->vm_mm->free_area_cache) - area->vm_mm->free_area_cache = area->vm_end; + if (addr > mm->free_area_cache) + mm->free_area_cache = addr; /* dont allow allocations above current base */ - if (area->vm_mm->free_area_cache > area->vm_mm->mmap_base) - area->vm_mm->free_area_cache = area->vm_mm->mmap_base; + if (mm->free_area_cache > mm->mmap_base) + mm->free_area_cache = mm->mmap_base; } unsigned long @@ -1595,7 +1617,6 @@ static void unmap_vma(struct mm_struct *mm, struct vm_area_struct *area) if (area->vm_flags & VM_LOCKED) area->vm_mm->locked_vm -= len >> PAGE_SHIFT; vm_stat_unaccount(area); - area->vm_mm->unmap_area(area); remove_vm_struct(area); } @@ -1649,6 +1670,7 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma, { struct vm_area_struct **insertion_point; struct vm_area_struct *tail_vma = NULL; + unsigned long addr; insertion_point = (prev ? &prev->vm_next : &mm->mmap); do { @@ -1659,6 +1681,11 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma, } while (vma && vma->vm_start < end); *insertion_point = vma; tail_vma->vm_next = NULL; + if (mm->unmap_area == arch_unmap_area) + addr = prev ? prev->vm_end : mm->mmap_base; + else + addr = vma ? vma->vm_start : mm->mmap_base; + mm->unmap_area(mm, addr); mm->mmap_cache = NULL; /* Kill the cache. */ } diff --git a/mm/nommu.c b/mm/nommu.c index c53e9c8..ce74452 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1067,7 +1067,7 @@ unsigned long arch_get_unmapped_area(struct file *file, unsigned long addr, return -ENOMEM; } -void arch_unmap_area(struct vm_area_struct *area) +void arch_unmap_area(struct mm_struct *mm, unsigned long addr) { } -- cgit v0.10.2 From 73219d178051691a56d57184d8c7f6d0cbe3c5c1 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Tue, 21 Jun 2005 17:14:52 -0700 Subject: [PATCH] mmap topdown fix for large stack limit, large allocation The topdown changes in 2.6.12-rc1 can cause large allocations with large stack limit to fail, despite there being space available. The mmap_base-len is only valid when len >= mmap_base. However, nothing in topdown allocator checks this. It's only (now) caught at higher level, which will cause allocation to simply fail. The following change restores the fallback to bottom-up path, which will allow large allocations with large stack limit to potentially still succeed. Signed-off-by: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/mmap.c b/mm/mmap.c index 9da23c1..da3fa90 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1267,6 +1267,9 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, return (mm->free_area_cache = addr-len); } + if (mm->mmap_base < len) + goto bottomup; + addr = mm->mmap_base-len; do { @@ -1288,6 +1291,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = vma->vm_start-len; } while (len < vma->vm_start); +bottomup: /* * A failed mmap() very likely causes application failure, * so fall back to the bottom-up function here. This scenario -- cgit v0.10.2 From cbe37d093707762fc0abb280781e6a82a9d8d568 Mon Sep 17 00:00:00 2001 From: Badari Pulavarty Date: Tue, 21 Jun 2005 17:14:52 -0700 Subject: [PATCH] mm: remove PG_highmem Remove PG_highmem, to save a page flag. Use is_highmem() instead. It'll generate a little more code, but we don't use PageHigheMem() in many places. Signed-off-by: Badari Pulavarty Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/frv/mm/init.c b/arch/frv/mm/init.c index 41958f5..7943315 100644 --- a/arch/frv/mm/init.c +++ b/arch/frv/mm/init.c @@ -169,7 +169,6 @@ void __init mem_init(void) struct page *page = &mem_map[pfn]; ClearPageReserved(page); - set_bit(PG_highmem, &page->flags); set_page_count(page, 1); __free_page(page); totalram_pages++; diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 7a7ea37..8766c77 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -269,7 +269,6 @@ void __init one_highpage_init(struct page *page, int pfn, int bad_ppro) { if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) { ClearPageReserved(page); - set_bit(PG_highmem, &page->flags); set_page_count(page, 1); __free_page(page); totalhigh_pages++; diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index b027ce7..73843c5 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -232,7 +232,6 @@ void __init mem_init(void) #ifdef CONFIG_LIMITED_DMA set_page_address(page, lowmem_page_address(page)); #endif - set_bit(PG_highmem, &page->flags); set_page_count(page, 1); __free_page(page); totalhigh_pages++; diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 363c157..c8529d0 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -469,7 +469,6 @@ void __init mem_init(void) struct page *page = mem_map + pfn; ClearPageReserved(page); - set_bit(PG_highmem, &page->flags); set_page_count(page, 1); __free_page(page); totalhigh_pages++; diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index a2dea69..ec2e050 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -384,7 +384,6 @@ void map_high_region(unsigned long start_pfn, unsigned long end_pfn) struct page *page = pfn_to_page(tmp); ClearPageReserved(page); - set_bit(PG_highmem, &page->flags); set_page_count(page, 1); __free_page(page); totalhigh_pages++; diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index c22825f..5597bd3 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -53,7 +53,6 @@ static void setup_highmem(unsigned long highmem_start, for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){ page = &mem_map[highmem_pfn + i]; ClearPageReserved(page); - set_bit(PG_highmem, &page->flags); set_page_count(page, 1); __free_page(page); } diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 39ab8c6..df31389 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -61,21 +61,20 @@ #define PG_active 6 #define PG_slab 7 /* slab debug (Suparna wants this) */ -#define PG_highmem 8 -#define PG_checked 9 /* kill me in 2.5.. */ -#define PG_arch_1 10 -#define PG_reserved 11 - -#define PG_private 12 /* Has something at ->private */ -#define PG_writeback 13 /* Page is under writeback */ -#define PG_nosave 14 /* Used for system suspend/resume */ -#define PG_compound 15 /* Part of a compound page */ - -#define PG_swapcache 16 /* Swap page: swp_entry_t in private */ -#define PG_mappedtodisk 17 /* Has blocks allocated on-disk */ -#define PG_reclaim 18 /* To be reclaimed asap */ -#define PG_nosave_free 19 /* Free, should not be written */ -#define PG_uncached 20 /* Page has been mapped as uncached */ +#define PG_checked 8 /* kill me in 2.5.. */ +#define PG_arch_1 9 +#define PG_reserved 10 +#define PG_private 11 /* Has something at ->private */ + +#define PG_writeback 12 /* Page is under writeback */ +#define PG_nosave 13 /* Used for system suspend/resume */ +#define PG_compound 14 /* Part of a compound page */ +#define PG_swapcache 15 /* Swap page: swp_entry_t in private */ + +#define PG_mappedtodisk 16 /* Has blocks allocated on-disk */ +#define PG_reclaim 17 /* To be reclaimed asap */ +#define PG_nosave_free 18 /* Free, should not be written */ +#define PG_uncached 19 /* Page has been mapped as uncached */ /* * Global page accounting. One instance per CPU. Only unsigned longs are @@ -215,7 +214,7 @@ extern void __mod_page_state(unsigned offset, unsigned long delta); #define TestSetPageSlab(page) test_and_set_bit(PG_slab, &(page)->flags) #ifdef CONFIG_HIGHMEM -#define PageHighMem(page) test_bit(PG_highmem, &(page)->flags) +#define PageHighMem(page) is_highmem(page_zone(page)) #else #define PageHighMem(page) 0 /* needed to optimize away at compile time */ #endif -- cgit v0.10.2 From 1ad539b2bd89bf2e129123eb24d5bcc4484a35de Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Tue, 21 Jun 2005 17:14:53 -0700 Subject: [PATCH] vm: try_to_free_pages unused argument try_to_free_pages accepts a third argument, order, but hasn't used it since before 2.6.0. The following patch removes the argument and updates all the calls to try_to_free_pages. Signed-off-by: Darren Hart Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/buffer.c b/fs/buffer.c index 7e9e409..0befa72 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -528,7 +528,7 @@ static void free_more_memory(void) for_each_pgdat(pgdat) { zones = pgdat->node_zonelists[GFP_NOFS&GFP_ZONEMASK].zones; if (*zones) - try_to_free_pages(zones, GFP_NOFS, 0); + try_to_free_pages(zones, GFP_NOFS); } } diff --git a/include/linux/swap.h b/include/linux/swap.h index 0d21e682..2343f99 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -172,7 +172,7 @@ extern int rotate_reclaimable_page(struct page *page); extern void swap_setup(void); /* linux/mm/vmscan.c */ -extern int try_to_free_pages(struct zone **, unsigned int, unsigned int); +extern int try_to_free_pages(struct zone **, unsigned int); extern int zone_reclaim(struct zone *, unsigned int, unsigned int); extern int shrink_all_memory(int); extern int vm_swappiness; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 95cbd30..70f7102 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -859,7 +859,7 @@ rebalance: reclaim_state.reclaimed_slab = 0; p->reclaim_state = &reclaim_state; - did_some_progress = try_to_free_pages(zones, gfp_mask, order); + did_some_progress = try_to_free_pages(zones, gfp_mask); p->reclaim_state = NULL; p->flags &= ~PF_MEMALLOC; diff --git a/mm/vmscan.c b/mm/vmscan.c index 24da725..4b8e62a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -919,8 +919,7 @@ shrink_caches(struct zone **zones, struct scan_control *sc) * holds filesystem locks which prevent writeout this might not work, and the * allocation attempt will fail. */ -int try_to_free_pages(struct zone **zones, - unsigned int gfp_mask, unsigned int order) +int try_to_free_pages(struct zone **zones, unsigned int gfp_mask) { int priority; int ret = 0; -- cgit v0.10.2 From 83e5d8f7253cb7b14472385a6d57df1e9f848e8e Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 21 Jun 2005 17:14:54 -0700 Subject: [PATCH] __mod_page_state(): pass unsigned long instead of unsigned By making the offset argument of __mod_page_state an unsigned long instead of unsigned, we can avoid forcing the compiler to sign extend a usually constant argument. This saves 1 instruction on x86-64. Signed-off-by: Benjamin LaHaise Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index df31389..f2ee9b2 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -136,7 +136,7 @@ struct page_state { extern void get_page_state(struct page_state *ret); extern void get_full_page_state(struct page_state *ret); extern unsigned long __read_page_state(unsigned offset); -extern void __mod_page_state(unsigned offset, unsigned long delta); +extern void __mod_page_state(unsigned long offset, unsigned long delta); #define read_page_state(member) \ __read_page_state(offsetof(struct page_state, member)) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 70f7102..c976628 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1158,7 +1158,7 @@ unsigned long __read_page_state(unsigned offset) return ret; } -void __mod_page_state(unsigned offset, unsigned long delta) +void __mod_page_state(unsigned long offset, unsigned long delta) { unsigned long flags; void* ptr; -- cgit v0.10.2 From c2f29ea111e3344ed48257c2a142c3db514e1529 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 21 Jun 2005 17:14:55 -0700 Subject: [PATCH] __read_page_state(): pass unsigned long instead of unsigned By making the offset argument of __read_page_state an unsigned long instead of unsigned, we can avoid forcing the compiler to sign extend a usually constant argument. This saves 1 instruction on x86-64. Signed-off-by: Benjamin LaHaise Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index f2ee9b2..f5a6695 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -135,7 +135,7 @@ struct page_state { extern void get_page_state(struct page_state *ret); extern void get_full_page_state(struct page_state *ret); -extern unsigned long __read_page_state(unsigned offset); +extern unsigned long __read_page_state(unsigned long offset); extern void __mod_page_state(unsigned long offset, unsigned long delta); #define read_page_state(member) \ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c976628..10446a6 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1144,7 +1144,7 @@ void get_full_page_state(struct page_state *ret) __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long)); } -unsigned long __read_page_state(unsigned offset) +unsigned long __read_page_state(unsigned long offset) { unsigned long ret = 0; int cpu; -- cgit v0.10.2 From 578c2fd6a7f378434655e5c480e23152a3994404 Mon Sep 17 00:00:00 2001 From: Janet Morgan Date: Tue, 21 Jun 2005 17:14:56 -0700 Subject: [PATCH] add OOM debug This patch provides more debug info when the system is OOM. It displays memory stats (basically sysrq-m info) from __alloc_pages() when page allocation fails and during OOM kill. Thanks to Dave Jones for coming up with the idea. Signed-off-by: Janet Morgan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 4bbb1cb..59666d9 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -258,6 +258,10 @@ void out_of_memory(unsigned int __nocast gfp_mask) struct mm_struct *mm = NULL; task_t * p; + printk("oom-killer: gfp_mask=0x%x\n", gfp_mask); + /* print memory stats */ + show_mem(); + read_lock(&tasklist_lock); retry: p = select_bad_process(); @@ -268,12 +272,9 @@ retry: /* Found nothing?!?! Either we hang forever, or we panic. */ if (!p) { read_unlock(&tasklist_lock); - show_free_areas(); panic("Out of memory and no killable processes...\n"); } - printk("oom-killer: gfp_mask=0x%x\n", gfp_mask); - show_free_areas(); mm = oom_kill_process(p); if (!mm) goto retry; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 10446a6..be05d17 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -935,6 +935,7 @@ nopage: " order:%d, mode:0x%x\n", p->comm, order, gfp_mask); dump_stack(); + show_mem(); } return NULL; got_pg: -- cgit v0.10.2 From 4ae7c03943fca73f23bc0cdb938070f41b98101f Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Tue, 21 Jun 2005 17:14:57 -0700 Subject: [PATCH] Periodically drain non local pagesets The pageset array can potentially acquire a huge amount of memory on large NUMA systems. F.e. on a system with 512 processors and 256 nodes there will be 256*512 pagesets. If each pageset only holds 5 pages then we are talking about 655360 pages.With a 16K page size on IA64 this results in potentially 10 Gigabytes of memory being trapped in pagesets. The typical cases are much less for smaller systems but there is still the potential of memory being trapped in off node pagesets. Off node memory may be rarely used if local memory is available and so we may potentially have memory in seldom used pagesets without this patch. The slab allocator flushes its per cpu caches every 2 seconds. The following patch flushes the off node pageset caches in the same way by tying into the slab flush. The patch also changes /proc/zoneinfo to include the number of pages currently in each pageset. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 208535f..8d6bf60 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -133,5 +133,10 @@ extern void FASTCALL(free_cold_page(struct page *page)); #define free_page(addr) free_pages((addr),0) void page_alloc_init(void); +#ifdef CONFIG_NUMA +void drain_remote_pages(void); +#else +static inline void drain_remote_pages(void) { }; +#endif #endif /* __LINUX_GFP_H */ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index be05d17..a95e72d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -516,6 +516,36 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, return allocated; } +#ifdef CONFIG_NUMA +/* Called from the slab reaper to drain remote pagesets */ +void drain_remote_pages(void) +{ + struct zone *zone; + int i; + unsigned long flags; + + local_irq_save(flags); + for_each_zone(zone) { + struct per_cpu_pageset *pset; + + /* Do not drain local pagesets */ + if (zone->zone_pgdat->node_id == numa_node_id()) + continue; + + pset = zone->pageset[smp_processor_id()]; + for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) { + struct per_cpu_pages *pcp; + + pcp = &pset->pcp[i]; + if (pcp->count) + pcp->count -= free_pages_bulk(zone, pcp->count, + &pcp->list, 0); + } + } + local_irq_restore(flags); +} +#endif + #if defined(CONFIG_PM) || defined(CONFIG_HOTPLUG_CPU) static void __drain_pages(unsigned int cpu) { @@ -1271,12 +1301,13 @@ void show_free_areas(void) pageset = zone_pcp(zone, cpu); for (temperature = 0; temperature < 2; temperature++) - printk("cpu %d %s: low %d, high %d, batch %d\n", + printk("cpu %d %s: low %d, high %d, batch %d used:%d\n", cpu, temperature ? "cold" : "hot", pageset->pcp[temperature].low, pageset->pcp[temperature].high, - pageset->pcp[temperature].batch); + pageset->pcp[temperature].batch, + pageset->pcp[temperature].count); } } diff --git a/mm/slab.c b/mm/slab.c index c78d343..93cbbbb 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2851,6 +2851,7 @@ next: } check_irq_on(); up(&cache_chain_sem); + drain_remote_pages(); /* Setup the next iteration */ schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC + smp_processor_id()); } -- cgit v0.10.2 From 2caaad41e4aa8f5dd999695b4ddeaa0e7f3912a4 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Tue, 21 Jun 2005 17:15:00 -0700 Subject: [PATCH] Reduce size of huge boot per_cpu_pageset Reduce size of the huge per_cpu_pageset structure in __initdata introduced into mm1 with the pageset localization patchset. Use one specially configured pageset per cpu for all zones and nodes during bootup. - Avoid duplication of pageset initialization code. - do the adding to the pageset list before potential free_pages_bulk in free_hot_cold_page (otherwise we would have to hold a page in a pageset during the period that the boot pagesets are in use). - remove mistaken __cpuinitdata attribute and revert back to __initdata for the boot pageset. A boot pageset is not necessary for cpu hotplug. Tested for UP SMP NUMA on x86_64 (2.6.12-rc6-mm1): UP SMP NUMA Tested on IA64 (2.6.12-rc5-mm2): NUMA (2.6.12-rc6-mm1 broken for IA64 because of sparsemem patches) Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index a95e72d..418102a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -71,11 +71,6 @@ EXPORT_SYMBOL(nr_swap_pages); struct zone *zone_table[1 << (ZONES_SHIFT + NODES_SHIFT)]; EXPORT_SYMBOL(zone_table); -#ifdef CONFIG_NUMA -static struct per_cpu_pageset - pageset_table[MAX_NR_ZONES*MAX_NUMNODES*NR_CPUS] __initdata; -#endif - static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" }; int min_free_kbytes = 1024; @@ -652,10 +647,10 @@ static void fastcall free_hot_cold_page(struct page *page, int cold) free_pages_check(__FUNCTION__, page); pcp = &zone_pcp(zone, get_cpu())->pcp[cold]; local_irq_save(flags); - if (pcp->count >= pcp->high) - pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0); list_add(&page->lru, &pcp->list); pcp->count++; + if (pcp->count >= pcp->high) + pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0); local_irq_restore(flags); put_cpu(); } @@ -1714,57 +1709,55 @@ static int __devinit zone_batchsize(struct zone *zone) return batch; } +inline void setup_pageset(struct per_cpu_pageset *p, unsigned long batch) +{ + struct per_cpu_pages *pcp; + + pcp = &p->pcp[0]; /* hot */ + pcp->count = 0; + pcp->low = 2 * batch; + pcp->high = 6 * batch; + pcp->batch = max(1UL, 1 * batch); + INIT_LIST_HEAD(&pcp->list); + + pcp = &p->pcp[1]; /* cold*/ + pcp->count = 0; + pcp->low = 0; + pcp->high = 2 * batch; + pcp->batch = max(1UL, 1 * batch); + INIT_LIST_HEAD(&pcp->list); +} + #ifdef CONFIG_NUMA /* - * Dynamicaly allocate memory for the + * Boot pageset table. One per cpu which is going to be used for all + * zones and all nodes. The parameters will be set in such a way + * that an item put on a list will immediately be handed over to + * the buddy list. This is safe since pageset manipulation is done + * with interrupts disabled. + * + * Some NUMA counter updates may also be caught by the boot pagesets. + * These will be discarded when bootup is complete. + */ +static struct per_cpu_pageset + boot_pageset[NR_CPUS] __initdata; + +/* + * Dynamically allocate memory for the * per cpu pageset array in struct zone. */ static int __devinit process_zones(int cpu) { struct zone *zone, *dzone; - int i; for_each_zone(zone) { - struct per_cpu_pageset *npageset = NULL; - npageset = kmalloc_node(sizeof(struct per_cpu_pageset), + zone->pageset[cpu] = kmalloc_node(sizeof(struct per_cpu_pageset), GFP_KERNEL, cpu_to_node(cpu)); - if (!npageset) { - zone->pageset[cpu] = NULL; + if (!zone->pageset[cpu]) goto bad; - } - if (zone->pageset[cpu]) { - memcpy(npageset, zone->pageset[cpu], - sizeof(struct per_cpu_pageset)); - - /* Relocate lists */ - for (i = 0; i < 2; i++) { - INIT_LIST_HEAD(&npageset->pcp[i].list); - list_splice(&zone->pageset[cpu]->pcp[i].list, - &npageset->pcp[i].list); - } - } else { - struct per_cpu_pages *pcp; - unsigned long batch; - - batch = zone_batchsize(zone); - - pcp = &npageset->pcp[0]; /* hot */ - pcp->count = 0; - pcp->low = 2 * batch; - pcp->high = 6 * batch; - pcp->batch = 1 * batch; - INIT_LIST_HEAD(&pcp->list); - - pcp = &npageset->pcp[1]; /* cold*/ - pcp->count = 0; - pcp->low = 0; - pcp->high = 2 * batch; - pcp->batch = 1 * batch; - INIT_LIST_HEAD(&pcp->list); - } - zone->pageset[cpu] = npageset; + setup_pageset(zone->pageset[cpu], zone_batchsize(zone)); } return 0; @@ -1878,30 +1871,13 @@ static void __init free_area_init_core(struct pglist_data *pgdat, batch = zone_batchsize(zone); for (cpu = 0; cpu < NR_CPUS; cpu++) { - struct per_cpu_pages *pcp; #ifdef CONFIG_NUMA - struct per_cpu_pageset *pgset; - pgset = &pageset_table[nid*MAX_NR_ZONES*NR_CPUS + - (j * NR_CPUS) + cpu]; - - zone->pageset[cpu] = pgset; + /* Early boot. Slab allocator not functional yet */ + zone->pageset[cpu] = &boot_pageset[cpu]; + setup_pageset(&boot_pageset[cpu],0); #else - struct per_cpu_pageset *pgset = zone_pcp(zone, cpu); + setup_pageset(zone_pcp(zone,cpu), batch); #endif - - pcp = &pgset->pcp[0]; /* hot */ - pcp->count = 0; - pcp->low = 2 * batch; - pcp->high = 6 * batch; - pcp->batch = 1 * batch; - INIT_LIST_HEAD(&pcp->list); - - pcp = &pgset->pcp[1]; /* cold */ - pcp->count = 0; - pcp->low = 0; - pcp->high = 2 * batch; - pcp->batch = 1 * batch; - INIT_LIST_HEAD(&pcp->list); } printk(KERN_DEBUG " %s zone: %lu pages, LIFO batch:%lu\n", zone_names[j], realsize, batch); -- cgit v0.10.2 From f14f75b81187cdbe10cc53a521bf9fdf97b59f8c Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Tue, 21 Jun 2005 17:15:02 -0700 Subject: [PATCH] ia64 uncached alloc This patch contains the ia64 uncached page allocator and the generic allocator (genalloc). The uncached allocator was formerly part of the SN2 mspec driver but there are several other users of it so it has been split off from the driver. The generic allocator can be used by device driver to manage special memory etc. The generic allocator is based on the allocator from the sym53c8xx_2 driver. Various users on ia64 needs uncached memory. The SGI SN architecture requires it for inter-partition communication between partitions within a large NUMA cluster. The specific user for this is the XPC code. Another application is large MPI style applications which use it for synchronization, on SN this can be done using special 'fetchop' operations but it also benefits non SN hardware which may use regular uncached memory for this purpose. Performance of doing this through uncached vs cached memory is pretty substantial. This is handled by the mspec driver which I will push out in a seperate patch. Rather than creating a specific allocator for just uncached memory I came up with genalloc which is a generic purpose allocator that can be used by device drivers and other subsystems as they please. For instance to handle onboard device memory. It was derived from the sym53c7xx_2 driver's allocator which is also an example of a potential user (I am refraining from modifying sym2 right now as it seems to have been under fairly heavy development recently). On ia64 memory has various properties within a granule, ie. it isn't safe to access memory as uncached within the same granule as currently has memory accessed in cached mode. The regular system therefore doesn't utilize memory in the lower granules which is mixed in with device PAL code etc. The uncached driver walks the EFI memmap and pulls out the spill uncached pages and sticks them into the uncached pool. Only after these chunks have been utilized, will it start converting regular cached memory into uncached memory. Hence the reason for the EFI related code additions. Signed-off-by: Jes Sorensen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 3ad2c4a..295b5ab 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -50,6 +50,10 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER bool default y +config IA64_UNCACHED_ALLOCATOR + bool + select GENERIC_ALLOCATOR + choice prompt "System type" default IA64_GENERIC diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index c1a02bb..4c73d8b 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_SMP) += smp.o smpboot.o domain.o obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o obj-$(CONFIG_IA64_CYCLONE) += cyclone.o obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o +obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o mca_recovery-y += mca_drv.o mca_drv_asm.o # The gate DSO image is built using a special linker script. diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 4a3b1aa..179f230 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -410,6 +410,38 @@ efi_memmap_walk (efi_freemem_callback_t callback, void *arg) } /* + * Walk the EFI memory map to pull out leftover pages in the lower + * memory regions which do not end up in the regular memory map and + * stick them into the uncached allocator + * + * The regular walk function is significantly more complex than the + * uncached walk which means it really doesn't make sense to try and + * marge the two. + */ +void __init +efi_memmap_walk_uc (efi_freemem_callback_t callback) +{ + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size, start, end; + + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + if (md->attribute == EFI_MEMORY_UC) { + start = PAGE_ALIGN(md->phys_addr); + end = PAGE_ALIGN((md->phys_addr+(md->num_pages << EFI_PAGE_SHIFT)) & PAGE_MASK); + if ((*callback)(start, end, NULL) < 0) + return; + } + } +} + + +/* * Look for the PAL_CODE region reported by EFI and maps it using an * ITR to enable safe PAL calls in virtual mode. See IA-64 Processor * Abstraction Layer chapter 11 in ADAG diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c new file mode 100644 index 0000000..490dfc9 --- /dev/null +++ b/arch/ia64/kernel/uncached.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * A simple uncached page allocator using the generic allocator. This + * allocator first utilizes the spare (spill) pages found in the EFI + * memmap and will then start converting cached pages to uncached ones + * at a granule at a time. Node awareness is implemented by having a + * pool of pages per node. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG 0 + +#if DEBUG +#define dprintk printk +#else +#define dprintk(x...) do { } while (0) +#endif + +void __init efi_memmap_walk_uc (efi_freemem_callback_t callback); + +#define MAX_UNCACHED_GRANULES 5 +static int allocated_granules; + +struct gen_pool *uncached_pool[MAX_NUMNODES]; + + +static void uncached_ipi_visibility(void *data) +{ + int status; + + status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL); + if ((status != PAL_VISIBILITY_OK) && + (status != PAL_VISIBILITY_OK_REMOTE_NEEDED)) + printk(KERN_DEBUG "pal_prefetch_visibility() returns %i on " + "CPU %i\n", status, get_cpu()); +} + + +static void uncached_ipi_mc_drain(void *data) +{ + int status; + status = ia64_pal_mc_drain(); + if (status) + printk(KERN_WARNING "ia64_pal_mc_drain() failed with %i on " + "CPU %i\n", status, get_cpu()); +} + + +static unsigned long +uncached_get_new_chunk(struct gen_pool *poolp) +{ + struct page *page; + void *tmp; + int status, i; + unsigned long addr, node; + + if (allocated_granules >= MAX_UNCACHED_GRANULES) + return 0; + + node = poolp->private; + page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, + IA64_GRANULE_SHIFT-PAGE_SHIFT); + + dprintk(KERN_INFO "get_new_chunk page %p, addr %lx\n", + page, (unsigned long)(page-vmem_map) << PAGE_SHIFT); + + /* + * Do magic if no mem on local node! XXX + */ + if (!page) + return 0; + tmp = page_address(page); + + /* + * There's a small race here where it's possible for someone to + * access the page through /dev/mem halfway through the conversion + * to uncached - not sure it's really worth bothering about + */ + for (i = 0; i < (IA64_GRANULE_SIZE / PAGE_SIZE); i++) + SetPageUncached(&page[i]); + + flush_tlb_kernel_range(tmp, tmp + IA64_GRANULE_SIZE); + + status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL); + + dprintk(KERN_INFO "pal_prefetch_visibility() returns %i on cpu %i\n", + status, get_cpu()); + + if (!status) { + status = smp_call_function(uncached_ipi_visibility, NULL, 0, 1); + if (status) + printk(KERN_WARNING "smp_call_function failed for " + "uncached_ipi_visibility! (%i)\n", status); + } + + if (ia64_platform_is("sn2")) + sn_flush_all_caches((unsigned long)tmp, IA64_GRANULE_SIZE); + else + flush_icache_range((unsigned long)tmp, + (unsigned long)tmp+IA64_GRANULE_SIZE); + + ia64_pal_mc_drain(); + status = smp_call_function(uncached_ipi_mc_drain, NULL, 0, 1); + if (status) + printk(KERN_WARNING "smp_call_function failed for " + "uncached_ipi_mc_drain! (%i)\n", status); + + addr = (unsigned long)tmp - PAGE_OFFSET + __IA64_UNCACHED_OFFSET; + + allocated_granules++; + return addr; +} + + +/* + * uncached_alloc_page + * + * Allocate 1 uncached page. Allocates on the requested node. If no + * uncached pages are available on the requested node, roundrobin starting + * with higher nodes. + */ +unsigned long +uncached_alloc_page(int nid) +{ + unsigned long maddr; + + maddr = gen_pool_alloc(uncached_pool[nid], PAGE_SIZE); + + dprintk(KERN_DEBUG "uncached_alloc_page returns %lx on node %i\n", + maddr, nid); + + /* + * If no memory is availble on our local node, try the + * remaining nodes in the system. + */ + if (!maddr) { + int i; + + for (i = MAX_NUMNODES - 1; i >= 0; i--) { + if (i == nid || !node_online(i)) + continue; + maddr = gen_pool_alloc(uncached_pool[i], PAGE_SIZE); + dprintk(KERN_DEBUG "uncached_alloc_page alternate search " + "returns %lx on node %i\n", maddr, i); + if (maddr) { + break; + } + } + } + + return maddr; +} +EXPORT_SYMBOL(uncached_alloc_page); + + +/* + * uncached_free_page + * + * Free a single uncached page. + */ +void +uncached_free_page(unsigned long maddr) +{ + int node; + + node = nasid_to_cnodeid(NASID_GET(maddr)); + + dprintk(KERN_DEBUG "uncached_free_page(%lx) on node %i\n", maddr, node); + + if ((maddr & (0XFUL << 60)) != __IA64_UNCACHED_OFFSET) + panic("uncached_free_page invalid address %lx\n", maddr); + + gen_pool_free(uncached_pool[node], maddr, PAGE_SIZE); +} +EXPORT_SYMBOL(uncached_free_page); + + +/* + * uncached_build_memmap, + * + * Called at boot time to build a map of pages that can be used for + * memory special operations. + */ +static int __init +uncached_build_memmap(unsigned long start, unsigned long end, void *arg) +{ + long length; + unsigned long vstart, vend; + int node; + + length = end - start; + vstart = start + __IA64_UNCACHED_OFFSET; + vend = end + __IA64_UNCACHED_OFFSET; + + dprintk(KERN_ERR "uncached_build_memmap(%lx %lx)\n", start, end); + + memset((char *)vstart, 0, length); + + node = nasid_to_cnodeid(NASID_GET(start)); + + for (; vstart < vend ; vstart += PAGE_SIZE) { + dprintk(KERN_INFO "sticking %lx into the pool!\n", vstart); + gen_pool_free(uncached_pool[node], vstart, PAGE_SIZE); + } + + return 0; +} + + +static int __init uncached_init(void) { + int i; + + for (i = 0; i < MAX_NUMNODES; i++) { + if (!node_online(i)) + continue; + uncached_pool[i] = gen_pool_create(0, IA64_GRANULE_SHIFT, + &uncached_get_new_chunk, i); + } + + efi_memmap_walk_uc(uncached_build_memmap); + + return 0; +} + +__initcall(uncached_init); diff --git a/include/asm-ia64/uncached.h b/include/asm-ia64/uncached.h new file mode 100644 index 0000000..b82d923 --- /dev/null +++ b/include/asm-ia64/uncached.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * Prototypes for the uncached page allocator + */ + +extern unsigned long uncached_alloc_page(int nid); +extern void uncached_free_page(unsigned long); diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h new file mode 100644 index 0000000..7fd0576 --- /dev/null +++ b/include/linux/genalloc.h @@ -0,0 +1,40 @@ +/* + * Basic general purpose allocator for managing special purpose memory + * not managed by the regular kmalloc/kfree interface. + * Uses for this includes on-device special memory, uncached memory + * etc. + * + * This code is based on the buddy allocator found in the sym53c8xx_2 + * driver, adapted for general purpose use. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include + +#define ALLOC_MIN_SHIFT 5 /* 32 bytes minimum */ +/* + * Link between free memory chunks of a given size. + */ +struct gen_pool_link { + struct gen_pool_link *next; +}; + +/* + * Memory pool descriptor. + */ +struct gen_pool { + spinlock_t lock; + unsigned long (*get_new_chunk)(struct gen_pool *); + struct gen_pool *next; + struct gen_pool_link *h; + unsigned long private; + int max_chunk_shift; +}; + +unsigned long gen_pool_alloc(struct gen_pool *poolp, int size); +void gen_pool_free(struct gen_pool *mp, unsigned long ptr, int size); +struct gen_pool *gen_pool_create(int nr_chunks, int max_chunk_shift, + unsigned long (*fp)(struct gen_pool *), + unsigned long data); diff --git a/lib/Kconfig b/lib/Kconfig index eeb4522..2d4d4e3 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -40,6 +40,12 @@ config ZLIB_DEFLATE tristate # +# Generic allocator support is selected if needed +# +config GENERIC_ALLOCATOR + boolean + +# # reed solomon support is select'ed if needed # config REED_SOLOMON diff --git a/lib/Makefile b/lib/Makefile index 5f10cb8..dcb4231 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o obj-$(CONFIG_CRC32) += crc32.o obj-$(CONFIG_LIBCRC32C) += libcrc32c.o obj-$(CONFIG_GENERIC_IOMAP) += iomap.o +obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/ obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/ diff --git a/lib/genalloc.c b/lib/genalloc.c new file mode 100644 index 0000000..d6d30d2e --- /dev/null +++ b/lib/genalloc.c @@ -0,0 +1,188 @@ +/* + * Basic general purpose allocator for managing special purpose memory + * not managed by the regular kmalloc/kfree interface. + * Uses for this includes on-device special memory, uncached memory + * etc. + * + * This code is based on the buddy allocator found in the sym53c8xx_2 + * driver Copyright (C) 1999-2001 Gerard Roudier , + * and adapted for general purpose use. + * + * Copyright 2005 (C) Jes Sorensen + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +struct gen_pool *gen_pool_create(int nr_chunks, int max_chunk_shift, + unsigned long (*fp)(struct gen_pool *), + unsigned long data) +{ + struct gen_pool *poolp; + unsigned long tmp; + int i; + + /* + * This is really an arbitrary limit, +10 is enough for + * IA64_GRANULE_SHIFT, aka 16MB. If anyone needs a large limit + * this can be increased without problems. + */ + if ((max_chunk_shift > (PAGE_SHIFT + 10)) || + ((max_chunk_shift < ALLOC_MIN_SHIFT) && max_chunk_shift)) + return NULL; + + if (!max_chunk_shift) + max_chunk_shift = PAGE_SHIFT; + + poolp = kmalloc(sizeof(struct gen_pool), GFP_KERNEL); + if (!poolp) + return NULL; + memset(poolp, 0, sizeof(struct gen_pool)); + poolp->h = kmalloc(sizeof(struct gen_pool_link) * + (max_chunk_shift - ALLOC_MIN_SHIFT + 1), + GFP_KERNEL); + if (!poolp->h) { + printk(KERN_WARNING "gen_pool_alloc() failed to allocate\n"); + kfree(poolp); + return NULL; + } + memset(poolp->h, 0, sizeof(struct gen_pool_link) * + (max_chunk_shift - ALLOC_MIN_SHIFT + 1)); + + spin_lock_init(&poolp->lock); + poolp->get_new_chunk = fp; + poolp->max_chunk_shift = max_chunk_shift; + poolp->private = data; + + for (i = 0; i < nr_chunks; i++) { + tmp = poolp->get_new_chunk(poolp); + printk(KERN_INFO "allocated %lx\n", tmp); + if (!tmp) + break; + gen_pool_free(poolp, tmp, (1 << poolp->max_chunk_shift)); + } + + return poolp; +} +EXPORT_SYMBOL(gen_pool_create); + + +/* + * Simple power of two buddy-like generic allocator. + * Provides naturally aligned memory chunks. + */ +unsigned long gen_pool_alloc(struct gen_pool *poolp, int size) +{ + int j, i, s, max_chunk_size; + unsigned long a, flags; + struct gen_pool_link *h = poolp->h; + + max_chunk_size = 1 << poolp->max_chunk_shift; + + if (size > max_chunk_size) + return 0; + + i = 0; + + size = max(size, 1 << ALLOC_MIN_SHIFT); + s = roundup_pow_of_two(size); + + j = i; + + spin_lock_irqsave(&poolp->lock, flags); + while (!h[j].next) { + if (s == max_chunk_size) { + struct gen_pool_link *ptr; + spin_unlock_irqrestore(&poolp->lock, flags); + ptr = (struct gen_pool_link *)poolp->get_new_chunk(poolp); + spin_lock_irqsave(&poolp->lock, flags); + h[j].next = ptr; + if (h[j].next) + h[j].next->next = NULL; + break; + } + j++; + s <<= 1; + } + a = (unsigned long) h[j].next; + if (a) { + h[j].next = h[j].next->next; + /* + * This should be split into a seperate function doing + * the chunk split in order to support custom + * handling memory not physically accessible by host + */ + while (j > i) { + j -= 1; + s >>= 1; + h[j].next = (struct gen_pool_link *) (a + s); + h[j].next->next = NULL; + } + } + spin_unlock_irqrestore(&poolp->lock, flags); + return a; +} +EXPORT_SYMBOL(gen_pool_alloc); + + +/* + * Counter-part of the generic allocator. + */ +void gen_pool_free(struct gen_pool *poolp, unsigned long ptr, int size) +{ + struct gen_pool_link *q; + struct gen_pool_link *h = poolp->h; + unsigned long a, b, flags; + int i, s, max_chunk_size; + + max_chunk_size = 1 << poolp->max_chunk_shift; + + if (size > max_chunk_size) + return; + + i = 0; + + size = max(size, 1 << ALLOC_MIN_SHIFT); + s = roundup_pow_of_two(size); + + a = ptr; + + spin_lock_irqsave(&poolp->lock, flags); + while (1) { + if (s == max_chunk_size) { + ((struct gen_pool_link *)a)->next = h[i].next; + h[i].next = (struct gen_pool_link *)a; + break; + } + b = a ^ s; + q = &h[i]; + + while (q->next && q->next != (struct gen_pool_link *)b) + q = q->next; + + if (!q->next) { + ((struct gen_pool_link *)a)->next = h[i].next; + h[i].next = (struct gen_pool_link *)a; + break; + } + q->next = q->next->next; + a = a & b; + s <<= 1; + i++; + } + spin_unlock_irqrestore(&poolp->lock, flags); +} +EXPORT_SYMBOL(gen_pool_free); -- cgit v0.10.2 From 65ed0b337bd2b47097cf6c772f024772513b7b0d Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Tue, 21 Jun 2005 17:15:03 -0700 Subject: [PATCH] SN2 XPC build patches This patch contains the bits to make the XPC code use the uncached allocator rather than calling into the mspec driver. It also includes the mspec.h header which is required to build the XPC modules. Signed-off-by: Jes Sorensen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 295b5ab..34e603c 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -227,7 +227,7 @@ config IA64_SGI_SN_SIM config IA64_SGI_SN_XP tristate "Support communication between SGI SSIs" - depends on MSPEC + select IA64_UNCACHED_ALLOCATOR help An SGI machine can be divided into multiple Single System Images which act independently of each other and have diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c index 2c3c4a8..cd7ed73 100644 --- a/arch/ia64/sn/kernel/xpc_partition.c +++ b/arch/ia64/sn/kernel/xpc_partition.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -183,7 +184,7 @@ xpc_rsvd_page_init(void) * memory protections are never restricted. */ if ((amos_page = xpc_vars->amos_page) == NULL) { - amos_page = (AMO_t *) mspec_kalloc_page(0); + amos_page = (AMO_t *) TO_AMO(uncached_alloc_page(0)); if (amos_page == NULL) { dev_err(xpc_part, "can't allocate page of AMOs\n"); return NULL; @@ -200,7 +201,8 @@ xpc_rsvd_page_init(void) if (ret != 0) { dev_err(xpc_part, "can't change memory " "protections\n"); - mspec_kfree_page((unsigned long) amos_page); + uncached_free_page(__IA64_UNCACHED_OFFSET | + TO_PHYS((u64) amos_page)); return NULL; } } diff --git a/include/asm-ia64/sn/mspec.h b/include/asm-ia64/sn/mspec.h new file mode 100644 index 0000000..dbe13c6 --- /dev/null +++ b/include/asm-ia64/sn/mspec.h @@ -0,0 +1,59 @@ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2001-2004 Silicon Graphics, Inc. All rights reserved. + */ + +#ifndef _ASM_IA64_SN_MSPEC_H +#define _ASM_IA64_SN_MSPEC_H + +#define FETCHOP_VAR_SIZE 64 /* 64 byte per fetchop variable */ + +#define FETCHOP_LOAD 0 +#define FETCHOP_INCREMENT 8 +#define FETCHOP_DECREMENT 16 +#define FETCHOP_CLEAR 24 + +#define FETCHOP_STORE 0 +#define FETCHOP_AND 24 +#define FETCHOP_OR 32 + +#define FETCHOP_CLEAR_CACHE 56 + +#define FETCHOP_LOAD_OP(addr, op) ( \ + *(volatile long *)((char*) (addr) + (op))) + +#define FETCHOP_STORE_OP(addr, op, x) ( \ + *(volatile long *)((char*) (addr) + (op)) = (long) (x)) + +#ifdef __KERNEL__ + +/* + * Each Atomic Memory Operation (AMO formerly known as fetchop) + * variable is 64 bytes long. The first 8 bytes are used. The + * remaining 56 bytes are unaddressable due to the operation taking + * that portion of the address. + * + * NOTE: The AMO_t _MUST_ be placed in either the first or second half + * of the cache line. The cache line _MUST NOT_ be used for anything + * other than additional AMO_t entries. This is because there are two + * addresses which reference the same physical cache line. One will + * be a cached entry with the memory type bits all set. This address + * may be loaded into processor cache. The AMO_t will be referenced + * uncached via the memory special memory type. If any portion of the + * cached cache-line is modified, when that line is flushed, it will + * overwrite the uncached value in physical memory and lead to + * inconsistency. + */ +typedef struct { + u64 variable; + u64 unused[7]; +} AMO_t; + + +#endif /* __KERNEL__ */ + +#endif /* _ASM_IA64_SN_MSPEC_H */ -- cgit v0.10.2 From 0edd73b33426df61b1d8a0a50d1f2ec097500abb Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Jun 2005 17:15:04 -0700 Subject: [PATCH] shmem: restore superblock info To improve shmem scalability, we allowed tmpfs instances which don't need their blocks or inodes limited not to count them, and not to allocate any sbinfo. Which was okay when the only use for the sbinfo was accounting blocks and inodes; but since then a couple of unrelated projects extending tmpfs want to store other data in the sbinfo. Whether either extension reaches mainline is beside the point: I'm guilty of a bad design decision, and should restore sbinfo to make any such future extensions easier. So, once again allocate a shmem_sb_info for every shmem/tmpfs instance, and now let max_blocks 0 indicate unlimited blocks, and max_inodes 0 unlimited inodes. Brent Casavant verified (many months ago) that this does not perceptibly impact the scalability (since the unlimited sbinfo cacheline is repeatedly accessed but only once dirtied). And merge shmem_set_size into its sole caller shmem_remount_fs. Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/filesystems/tmpfs.txt b/Documentation/filesystems/tmpfs.txt index 417e309..0d783c5 100644 --- a/Documentation/filesystems/tmpfs.txt +++ b/Documentation/filesystems/tmpfs.txt @@ -71,8 +71,8 @@ can be changed on remount. The size parameter also accepts a suffix % to limit this tmpfs instance to that percentage of your physical RAM: the default, when neither size nor nr_blocks is specified, is size=50% -If both nr_blocks (or size) and nr_inodes are set to 0, neither blocks -nor inodes will be limited in that instance. It is generally unwise to +If nr_blocks=0 (or size=0), blocks will not be limited in that instance; +if nr_inodes=0, inodes will not be limited. It is generally unwise to mount with such options, since it allows any user with write access to use up all the memory on the machine; but enhances the scalability of that instance in a system with many cpus making intensive use of it. @@ -97,4 +97,4 @@ RAM/SWAP in 10240 inodes and it is only accessible by root. Author: Christoph Rohland , 1.12.01 Updated: - Hugh Dickins , 01 September 2004 + Hugh Dickins , 13 March 2005 diff --git a/mm/shmem.c b/mm/shmem.c index 61574b8..e64fa72 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -6,8 +6,8 @@ * 2000-2001 Christoph Rohland * 2000-2001 SAP AG * 2002 Red Hat Inc. - * Copyright (C) 2002-2004 Hugh Dickins. - * Copyright (C) 2002-2004 VERITAS Software Corporation. + * Copyright (C) 2002-2005 Hugh Dickins. + * Copyright (C) 2002-2005 VERITAS Software Corporation. * Copyright (C) 2004 Andi Kleen, SuSE Labs * * Extended attribute support for tmpfs: @@ -194,7 +194,7 @@ static DEFINE_SPINLOCK(shmem_swaplist_lock); static void shmem_free_blocks(struct inode *inode, long pages) { struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - if (sbinfo) { + if (sbinfo->max_blocks) { spin_lock(&sbinfo->stat_lock); sbinfo->free_blocks += pages; inode->i_blocks -= pages*BLOCKS_PER_PAGE; @@ -357,7 +357,7 @@ static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, unsigned long * page (and perhaps indirect index pages) yet to allocate: * a waste to allocate index if we cannot allocate data. */ - if (sbinfo) { + if (sbinfo->max_blocks) { spin_lock(&sbinfo->stat_lock); if (sbinfo->free_blocks <= 1) { spin_unlock(&sbinfo->stat_lock); @@ -677,8 +677,8 @@ static void shmem_delete_inode(struct inode *inode) spin_unlock(&shmem_swaplist_lock); } } - if (sbinfo) { - BUG_ON(inode->i_blocks); + BUG_ON(inode->i_blocks); + if (sbinfo->max_inodes) { spin_lock(&sbinfo->stat_lock); sbinfo->free_inodes++; spin_unlock(&sbinfo->stat_lock); @@ -1080,7 +1080,7 @@ repeat: } else { shmem_swp_unmap(entry); sbinfo = SHMEM_SB(inode->i_sb); - if (sbinfo) { + if (sbinfo->max_blocks) { spin_lock(&sbinfo->stat_lock); if (sbinfo->free_blocks == 0 || shmem_acct_block(info->flags)) { @@ -1269,7 +1269,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) struct shmem_inode_info *info; struct shmem_sb_info *sbinfo = SHMEM_SB(sb); - if (sbinfo) { + if (sbinfo->max_inodes) { spin_lock(&sbinfo->stat_lock); if (!sbinfo->free_inodes) { spin_unlock(&sbinfo->stat_lock); @@ -1319,7 +1319,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) mpol_shared_policy_init(&info->policy); break; } - } else if (sbinfo) { + } else if (sbinfo->max_inodes) { spin_lock(&sbinfo->stat_lock); sbinfo->free_inodes++; spin_unlock(&sbinfo->stat_lock); @@ -1328,31 +1328,6 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) } #ifdef CONFIG_TMPFS - -static int shmem_set_size(struct shmem_sb_info *sbinfo, - unsigned long max_blocks, unsigned long max_inodes) -{ - int error; - unsigned long blocks, inodes; - - spin_lock(&sbinfo->stat_lock); - blocks = sbinfo->max_blocks - sbinfo->free_blocks; - inodes = sbinfo->max_inodes - sbinfo->free_inodes; - error = -EINVAL; - if (max_blocks < blocks) - goto out; - if (max_inodes < inodes) - goto out; - error = 0; - sbinfo->max_blocks = max_blocks; - sbinfo->free_blocks = max_blocks - blocks; - sbinfo->max_inodes = max_inodes; - sbinfo->free_inodes = max_inodes - inodes; -out: - spin_unlock(&sbinfo->stat_lock); - return error; -} - static struct inode_operations shmem_symlink_inode_operations; static struct inode_operations shmem_symlink_inline_operations; @@ -1607,15 +1582,17 @@ static int shmem_statfs(struct super_block *sb, struct kstatfs *buf) buf->f_type = TMPFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; buf->f_namelen = NAME_MAX; - if (sbinfo) { - spin_lock(&sbinfo->stat_lock); + spin_lock(&sbinfo->stat_lock); + if (sbinfo->max_blocks) { buf->f_blocks = sbinfo->max_blocks; buf->f_bavail = buf->f_bfree = sbinfo->free_blocks; + } + if (sbinfo->max_inodes) { buf->f_files = sbinfo->max_inodes; buf->f_ffree = sbinfo->free_inodes; - spin_unlock(&sbinfo->stat_lock); } /* else leave those fields 0 like simple_statfs */ + spin_unlock(&sbinfo->stat_lock); return 0; } @@ -1672,7 +1649,7 @@ static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentr * but each new link needs a new dentry, pinning lowmem, and * tmpfs dentries cannot be pruned until they are unlinked. */ - if (sbinfo) { + if (sbinfo->max_inodes) { spin_lock(&sbinfo->stat_lock); if (!sbinfo->free_inodes) { spin_unlock(&sbinfo->stat_lock); @@ -1697,7 +1674,7 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry) if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode)) { struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - if (sbinfo) { + if (sbinfo->max_inodes) { spin_lock(&sbinfo->stat_lock); sbinfo->free_inodes++; spin_unlock(&sbinfo->stat_lock); @@ -1921,22 +1898,42 @@ bad_val: static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) { struct shmem_sb_info *sbinfo = SHMEM_SB(sb); - unsigned long max_blocks = 0; - unsigned long max_inodes = 0; + unsigned long max_blocks = sbinfo->max_blocks; + unsigned long max_inodes = sbinfo->max_inodes; + unsigned long blocks; + unsigned long inodes; + int error = -EINVAL; + + if (shmem_parse_options(data, NULL, NULL, NULL, + &max_blocks, &max_inodes)) + return error; - if (sbinfo) { - max_blocks = sbinfo->max_blocks; - max_inodes = sbinfo->max_inodes; - } - if (shmem_parse_options(data, NULL, NULL, NULL, &max_blocks, &max_inodes)) - return -EINVAL; - /* Keep it simple: disallow limited <-> unlimited remount */ - if ((max_blocks || max_inodes) == !sbinfo) - return -EINVAL; - /* But allow the pointless unlimited -> unlimited remount */ - if (!sbinfo) - return 0; - return shmem_set_size(sbinfo, max_blocks, max_inodes); + spin_lock(&sbinfo->stat_lock); + blocks = sbinfo->max_blocks - sbinfo->free_blocks; + inodes = sbinfo->max_inodes - sbinfo->free_inodes; + if (max_blocks < blocks) + goto out; + if (max_inodes < inodes) + goto out; + /* + * Those tests also disallow limited->unlimited while any are in + * use, so i_blocks will always be zero when max_blocks is zero; + * but we must separately disallow unlimited->limited, because + * in that case we have no record of how much is already in use. + */ + if (max_blocks && !sbinfo->max_blocks) + goto out; + if (max_inodes && !sbinfo->max_inodes) + goto out; + + error = 0; + sbinfo->max_blocks = max_blocks; + sbinfo->free_blocks = max_blocks - blocks; + sbinfo->max_inodes = max_inodes; + sbinfo->free_inodes = max_inodes - inodes; +out: + spin_unlock(&sbinfo->stat_lock); + return error; } #endif @@ -1961,11 +1958,11 @@ static int shmem_fill_super(struct super_block *sb, uid_t uid = current->fsuid; gid_t gid = current->fsgid; int err = -ENOMEM; - -#ifdef CONFIG_TMPFS + struct shmem_sb_info *sbinfo; unsigned long blocks = 0; unsigned long inodes = 0; +#ifdef CONFIG_TMPFS /* * Per default we only allow half of the physical ram per * tmpfs instance, limiting inodes to one per page of lowmem; @@ -1976,34 +1973,34 @@ static int shmem_fill_super(struct super_block *sb, inodes = totalram_pages - totalhigh_pages; if (inodes > blocks) inodes = blocks; - - if (shmem_parse_options(data, &mode, - &uid, &gid, &blocks, &inodes)) + if (shmem_parse_options(data, &mode, &uid, &gid, + &blocks, &inodes)) return -EINVAL; } - - if (blocks || inodes) { - struct shmem_sb_info *sbinfo; - sbinfo = kmalloc(sizeof(struct shmem_sb_info), GFP_KERNEL); - if (!sbinfo) - return -ENOMEM; - sb->s_fs_info = sbinfo; - spin_lock_init(&sbinfo->stat_lock); - sbinfo->max_blocks = blocks; - sbinfo->free_blocks = blocks; - sbinfo->max_inodes = inodes; - sbinfo->free_inodes = inodes; - } - sb->s_xattr = shmem_xattr_handlers; #else sb->s_flags |= MS_NOUSER; #endif + /* Round up to L1_CACHE_BYTES to resist false sharing */ + sbinfo = kmalloc(max((int)sizeof(struct shmem_sb_info), + L1_CACHE_BYTES), GFP_KERNEL); + if (!sbinfo) + return -ENOMEM; + + spin_lock_init(&sbinfo->stat_lock); + sbinfo->max_blocks = blocks; + sbinfo->free_blocks = blocks; + sbinfo->max_inodes = inodes; + sbinfo->free_inodes = inodes; + + sb->s_fs_info = sbinfo; sb->s_maxbytes = SHMEM_MAX_BYTES; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = TMPFS_MAGIC; sb->s_op = &shmem_ops; + sb->s_xattr = shmem_xattr_handlers; + inode = shmem_get_inode(sb, S_IFDIR | mode, 0); if (!inode) goto failed; -- cgit v0.10.2 From 400e65146c428d2ef677a927786fda2cec545a76 Mon Sep 17 00:00:00 2001 From: Bob Picco Date: Tue, 21 Jun 2005 17:15:05 -0700 Subject: [PATCH] ia64: pfn_to_nid() implementation pfn_to_nid is undefined. We haven't had this interface on ia64. The sys_mbind patches need it. Oh, the paddr_to_nid call could fail when DISCONTIG+NUMA is configured because there isn't any ACPI SRAT NUMA information. Signed-off-by: Bob Picco Acked-by: Tony Luck Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-ia64/mmzone.h b/include/asm-ia64/mmzone.h index 9491dac..83ca404 100644 --- a/include/asm-ia64/mmzone.h +++ b/include/asm-ia64/mmzone.h @@ -15,6 +15,20 @@ #include #include +static inline int pfn_to_nid(unsigned long pfn) +{ +#ifdef CONFIG_NUMA + extern int paddr_to_nid(unsigned long); + int nid = paddr_to_nid(pfn << PAGE_SHIFT); + if (nid < 0) + return 0; + else + return nid; +#else + return 0; +#endif +} + #ifdef CONFIG_DISCONTIGMEM #ifdef CONFIG_IA64_DIG /* DIG systems are small */ -- cgit v0.10.2 From 941150a326be88af245034ef4b3e9fa00229aa2d Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Jun 2005 17:15:06 -0700 Subject: [PATCH] mbind: fix verify_pages pte_page Strict mbind's check that pages already mapped are on right node has been using pte_page without checking if pfn_valid, and without page_table_lock to prevent spurious failures when try_to_unmap_one intervenes between the pte_present and the pte_page. Signed-off-by: Hugh Dickins Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 39252c7..c512cc9 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -242,6 +242,9 @@ static int verify_pages(struct mm_struct *mm, unsigned long addr, unsigned long end, unsigned long *nodes) { + int err = 0; + + spin_lock(&mm->page_table_lock); while (addr < end) { struct page *p; pte_t *pte; @@ -268,17 +271,23 @@ verify_pages(struct mm_struct *mm, } p = NULL; pte = pte_offset_map(pmd, addr); - if (pte_present(*pte)) - p = pte_page(*pte); + if (pte_present(*pte)) { + unsigned long pfn = pte_pfn(*pte); + if (pfn_valid(pfn)) + p = pfn_to_page(pfn); + } pte_unmap(pte); if (p) { unsigned nid = page_to_nid(p); - if (!test_bit(nid, nodes)) - return -EIO; + if (!test_bit(nid, nodes)) { + err = -EIO; + break; + } } addr += PAGE_SIZE; } - return 0; + spin_unlock(&mm->page_table_lock); + return err; } /* Step 1: check the range */ -- cgit v0.10.2 From 91612e0df20a52f61db3cac280c153311b36df7a Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Jun 2005 17:15:07 -0700 Subject: [PATCH] mbind: check_range use standard ptwalk Strict mbind's check for currently mapped pages being on node has been using a slow loop which re-evaluates pgd, pud, pmd, pte for each entry: replace that by a standard four-level page table walk like others in mm. Since mmap_sem is held for writing, page_table_lock can be taken at the inner level to limit latency. Signed-off-by: Hugh Dickins Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/mempolicy.c b/mm/mempolicy.c index c512cc9..cb41c31 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -238,56 +238,81 @@ static struct mempolicy *mpol_new(int mode, unsigned long *nodes) } /* Ensure all existing pages follow the policy. */ -static int -verify_pages(struct mm_struct *mm, - unsigned long addr, unsigned long end, unsigned long *nodes) +static int check_pte_range(struct mm_struct *mm, pmd_t *pmd, + unsigned long addr, unsigned long end, unsigned long *nodes) { - int err = 0; + pte_t *orig_pte; + pte_t *pte; spin_lock(&mm->page_table_lock); - while (addr < end) { - struct page *p; - pte_t *pte; - pmd_t *pmd; - pud_t *pud; - pgd_t *pgd; - pgd = pgd_offset(mm, addr); - if (pgd_none(*pgd)) { - unsigned long next = (addr + PGDIR_SIZE) & PGDIR_MASK; - if (next > addr) - break; - addr = next; - continue; - } - pud = pud_offset(pgd, addr); - if (pud_none(*pud)) { - addr = (addr + PUD_SIZE) & PUD_MASK; + orig_pte = pte = pte_offset_map(pmd, addr); + do { + unsigned long pfn; + unsigned int nid; + + if (!pte_present(*pte)) continue; - } - pmd = pmd_offset(pud, addr); - if (pmd_none(*pmd)) { - addr = (addr + PMD_SIZE) & PMD_MASK; + pfn = pte_pfn(*pte); + if (!pfn_valid(pfn)) continue; - } - p = NULL; - pte = pte_offset_map(pmd, addr); - if (pte_present(*pte)) { - unsigned long pfn = pte_pfn(*pte); - if (pfn_valid(pfn)) - p = pfn_to_page(pfn); - } - pte_unmap(pte); - if (p) { - unsigned nid = page_to_nid(p); - if (!test_bit(nid, nodes)) { - err = -EIO; - break; - } - } - addr += PAGE_SIZE; - } + nid = pfn_to_nid(pfn); + if (!test_bit(nid, nodes)) + break; + } while (pte++, addr += PAGE_SIZE, addr != end); + pte_unmap(orig_pte); spin_unlock(&mm->page_table_lock); - return err; + return addr != end; +} + +static inline int check_pmd_range(struct mm_struct *mm, pud_t *pud, + unsigned long addr, unsigned long end, unsigned long *nodes) +{ + pmd_t *pmd; + unsigned long next; + + pmd = pmd_offset(pud, addr); + do { + next = pmd_addr_end(addr, end); + if (pmd_none_or_clear_bad(pmd)) + continue; + if (check_pte_range(mm, pmd, addr, next, nodes)) + return -EIO; + } while (pmd++, addr = next, addr != end); + return 0; +} + +static inline int check_pud_range(struct mm_struct *mm, pgd_t *pgd, + unsigned long addr, unsigned long end, unsigned long *nodes) +{ + pud_t *pud; + unsigned long next; + + pud = pud_offset(pgd, addr); + do { + next = pud_addr_end(addr, end); + if (pud_none_or_clear_bad(pud)) + continue; + if (check_pmd_range(mm, pud, addr, next, nodes)) + return -EIO; + } while (pud++, addr = next, addr != end); + return 0; +} + +static inline int check_pgd_range(struct mm_struct *mm, + unsigned long addr, unsigned long end, unsigned long *nodes) +{ + pgd_t *pgd; + unsigned long next; + + pgd = pgd_offset(mm, addr); + do { + next = pgd_addr_end(addr, end); + if (pgd_none_or_clear_bad(pgd)) + continue; + if (check_pud_range(mm, pgd, addr, next, nodes)) + return -EIO; + } while (pgd++, addr = next, addr != end); + return 0; } /* Step 1: check the range */ @@ -308,7 +333,7 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end, if (prev && prev->vm_end < vma->vm_start) return ERR_PTR(-EFAULT); if ((flags & MPOL_MF_STRICT) && !is_vm_hugetlb_page(vma)) { - err = verify_pages(vma->vm_mm, + err = check_pgd_range(vma->vm_mm, vma->vm_start, vma->vm_end, nodes); if (err) { first = ERR_PTR(err); -- cgit v0.10.2 From 45918e1a8bfcabc1cb4570b8df276655020eac45 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Jun 2005 17:15:08 -0700 Subject: [PATCH] dup_mmap: update comment on new vma Remove part of comment on linking new vma in dup_mmap: since anon_vma rmap came in, try_to_unmap_one knows the vma without needing find_vma. But add a comment to note that here vma is inserted without mmap_sem. Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/fork.c b/kernel/fork.c index 876b31c..a28d11e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -250,8 +250,9 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) /* * Link in the new vma and copy the page table entries: - * link in first so that swapoff can see swap entries, - * and try_to_unmap_one's find_vma find the new vma. + * link in first so that swapoff can see swap entries. + * Note that, exceptionally, here the vma is inserted + * without holding mm->mmap_sem. */ spin_lock(&mm->page_table_lock); *pprev = tmp; -- cgit v0.10.2 From 334795eca421287c41c257992027d29659dc0f97 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Jun 2005 17:15:08 -0700 Subject: [PATCH] bad_page: clear reclaim and slab Since free_pages_check complains if PG_reclaim or PG_slab is set, bad_page ought to clear them to avoid repetitive reports (Nikita noticed this too). Let prep_new_page check page_count and PG_slab as free_pages_check does. Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 418102a..62b9509 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -105,11 +105,13 @@ static void bad_page(const char *function, struct page *page) printk(KERN_EMERG "Backtrace:\n"); dump_stack(); printk(KERN_EMERG "Trying to fix it up, but a reboot is needed\n"); - page->flags &= ~(1 << PG_private | + page->flags &= ~(1 << PG_lru | + 1 << PG_private | 1 << PG_locked | - 1 << PG_lru | 1 << PG_active | 1 << PG_dirty | + 1 << PG_reclaim | + 1 << PG_slab | 1 << PG_swapcache | 1 << PG_writeback); set_page_count(page, 0); @@ -440,14 +442,17 @@ void set_page_refs(struct page *page, int order) */ static void prep_new_page(struct page *page, int order) { - if (page->mapping || page_mapcount(page) || - (page->flags & ( + if ( page_mapcount(page) || + page->mapping != NULL || + page_count(page) != 0 || + (page->flags & ( + 1 << PG_lru | 1 << PG_private | 1 << PG_locked | - 1 << PG_lru | 1 << PG_active | 1 << PG_dirty | 1 << PG_reclaim | + 1 << PG_slab | 1 << PG_swapcache | 1 << PG_writeback ))) bad_page(__FUNCTION__, page); -- cgit v0.10.2 From 7c2f3fda5666c280bcd00ac3b86963270b23e796 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Jun 2005 17:15:09 -0700 Subject: [PATCH] rme96xx: fix PageReserved range rme96xx busmaster_malloc miscalculates and fails to set PageReserved on any page of char *buf; but busmaster_free does it right, so do the same (I don't have the card, just noticed this while sifting for rmap BUGs). Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c index 76774bb..b4278ee 100644 --- a/sound/oss/rme96xx.c +++ b/sound/oss/rme96xx.c @@ -807,7 +807,7 @@ static void* busmaster_malloc(int size) { struct page* page, *last_page; page = virt_to_page(buf); - last_page = virt_to_page(buf + (1 << pg)); + last_page = page + (1 << pg); DBG(printk("setting reserved bit\n")); while (page < last_page) { SetPageReserved(page); -- cgit v0.10.2 From 08ef472937e918875a82fd350d3de138aac50414 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Jun 2005 17:15:10 -0700 Subject: [PATCH] get_user_pages: kill get_page_map Since its birth, get_user_pages has been calling a misguided get_page_map function. follow_page has already returned NULL if the pfn is invalid, we cannot reach an invalid pfn from a validated struct page. Remove get_page_map, and the messy rewind in get_user_pages to cope with its failure. Oh, and could we please call that "struct page *page" like everywhere else, instead of "struct page *map"? Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory.c b/mm/memory.c index d209f74..b8846cf 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -840,23 +840,8 @@ check_user_page_readable(struct mm_struct *mm, unsigned long address) { return __follow_page(mm, address, /*read*/1, /*write*/0) != NULL; } - EXPORT_SYMBOL(check_user_page_readable); -/* - * Given a physical address, is there a useful struct page pointing to - * it? This may become more complex in the future if we start dealing - * with IO-aperture pages for direct-IO. - */ - -static inline struct page *get_page_map(struct page *page) -{ - if (!pfn_valid(page_to_pfn(page))) - return NULL; - return page; -} - - static inline int untouched_anonymous_page(struct mm_struct* mm, struct vm_area_struct *vma, unsigned long address) @@ -887,7 +872,6 @@ untouched_anonymous_page(struct mm_struct* mm, struct vm_area_struct *vma, return 0; } - int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int len, int write, int force, struct page **pages, struct vm_area_struct **vmas) @@ -951,21 +935,21 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, } spin_lock(&mm->page_table_lock); do { - struct page *map; + struct page *page; int lookup_write = write; cond_resched_lock(&mm->page_table_lock); - while (!(map = follow_page(mm, start, lookup_write))) { + while (!(page = follow_page(mm, start, lookup_write))) { /* * Shortcut for anonymous pages. We don't want * to force the creation of pages tables for - * insanly big anonymously mapped areas that + * insanely big anonymously mapped areas that * nobody touched so far. This is important * for doing a core dump for these mappings. */ if (!lookup_write && untouched_anonymous_page(mm,vma,start)) { - map = ZERO_PAGE(start); + page = ZERO_PAGE(start); break; } spin_unlock(&mm->page_table_lock); @@ -994,30 +978,21 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, spin_lock(&mm->page_table_lock); } if (pages) { - pages[i] = get_page_map(map); - if (!pages[i]) { - spin_unlock(&mm->page_table_lock); - while (i--) - page_cache_release(pages[i]); - i = -EFAULT; - goto out; - } - flush_dcache_page(pages[i]); - if (!PageReserved(pages[i])) - page_cache_get(pages[i]); + pages[i] = page; + flush_dcache_page(page); + if (!PageReserved(page)) + page_cache_get(page); } if (vmas) vmas[i] = vma; i++; start += PAGE_SIZE; len--; - } while(len && start < vma->vm_end); + } while (len && start < vma->vm_end); spin_unlock(&mm->page_table_lock); - } while(len); -out: + } while (len); return i; } - EXPORT_SYMBOL(get_user_pages); static int zeromap_pte_range(struct mm_struct *mm, pmd_t *pmd, -- cgit v0.10.2 From d296e9cd02c92e576ecce5344026a4df4353cdb2 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Jun 2005 17:15:11 -0700 Subject: [PATCH] do_wp_page: cannot share file page A small optimization to do_wp_page's check for whether to avoid copy by reusing the page already mapped. It can never share a cached file page, nor can it share a reserved page (often the empty zero page), so it's a waste of time to lock and unlock in those cases. Which nowadays can both be neatly excluded by a preliminary PageAnon test. Christoph has reported that a preliminary page_count test proved valuable for scalability here, but PageAnon covers more common cases all at once. Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory.c b/mm/memory.c index b8846cf..1c0a3db 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1239,7 +1239,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, } old_page = pfn_to_page(pfn); - if (!TestSetPageLocked(old_page)) { + if (PageAnon(old_page) && !TestSetPageLocked(old_page)) { int reuse = can_share_swap_page(old_page); unlock_page(old_page); if (reuse) { -- cgit v0.10.2 From c475a8ab625d567eacf5e30ec35d6d8704558062 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Jun 2005 17:15:12 -0700 Subject: [PATCH] can_share_swap_page: use page_mapcount Remember that ironic get_user_pages race? when the raised page_count on a page swapped out led do_wp_page to decide that it had to copy on write, so substituted a different page into userspace. 2.6.7 onwards have Andrea's solution, where try_to_unmap_one backs out if it finds page_count raised. Which works, but is unsatisfying (rmap.c has no other page_count heuristics), and was found a few months ago to hang an intensive page migration test. A year ago I was hesitant to engage page_mapcount, now it seems the right fix. So remove the page_count hack from try_to_unmap_one; and use activate_page in unuse_mm when dropping lock, to replace its secondary effect of helping swapoff to make progress in that case. Simplify can_share_swap_page (now called only on anonymous pages) to check page_mapcount + page_swapcount == 1: still needs the page lock to stabilize their (pessimistic) sum, but does not need swapper_space.tree_lock for that. In do_swap_page, move swap_free and unlock_page below page_add_anon_rmap, to keep sum on the high side, and correct when can_share_swap_page called. Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory.c b/mm/memory.c index 1c0a3db..da91b7b 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1686,10 +1686,6 @@ static int do_swap_page(struct mm_struct * mm, } /* The page isn't present yet, go ahead with the fault. */ - - swap_free(entry); - if (vm_swap_full()) - remove_exclusive_swap_page(page); inc_mm_counter(mm, rss); pte = mk_pte(page, vma->vm_page_prot); @@ -1697,12 +1693,16 @@ static int do_swap_page(struct mm_struct * mm, pte = maybe_mkwrite(pte_mkdirty(pte), vma); write_access = 0; } - unlock_page(page); flush_icache_page(vma, page); set_pte_at(mm, address, page_table, pte); page_add_anon_rmap(page, vma, address); + swap_free(entry); + if (vm_swap_full()) + remove_exclusive_swap_page(page); + unlock_page(page); + if (write_access) { if (do_wp_page(mm, vma, address, page_table, pmd, pte) == VM_FAULT_OOM) diff --git a/mm/rmap.c b/mm/rmap.c index 9827409..89770bd 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -539,27 +539,6 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma) goto out_unmap; } - /* - * Don't pull an anonymous page out from under get_user_pages. - * GUP carefully breaks COW and raises page count (while holding - * page_table_lock, as we have here) to make sure that the page - * cannot be freed. If we unmap that page here, a user write - * access to the virtual address will bring back the page, but - * its raised count will (ironically) be taken to mean it's not - * an exclusive swap page, do_wp_page will replace it by a copy - * page, and the user never get to see the data GUP was holding - * the original page for. - * - * This test is also useful for when swapoff (unuse_process) has - * to drop page lock: its reference to the page stops existing - * ptes from being unmapped, so swapoff can make progress. - */ - if (PageSwapCache(page) && - page_count(page) != page_mapcount(page) + 2) { - ret = SWAP_FAIL; - goto out_unmap; - } - /* Nuke the page table entry. */ flush_cache_page(vma, address, page_to_pfn(page)); pteval = ptep_clear_flush(vma, address, pte); diff --git a/mm/swapfile.c b/mm/swapfile.c index da48405..60cd24a 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -276,61 +276,37 @@ void swap_free(swp_entry_t entry) } /* - * Check if we're the only user of a swap page, - * when the page is locked. + * How many references to page are currently swapped out? */ -static int exclusive_swap_page(struct page *page) +static inline int page_swapcount(struct page *page) { - int retval = 0; - struct swap_info_struct * p; + int count = 0; + struct swap_info_struct *p; swp_entry_t entry; entry.val = page->private; p = swap_info_get(entry); if (p) { - /* Is the only swap cache user the cache itself? */ - if (p->swap_map[swp_offset(entry)] == 1) { - /* Recheck the page count with the swapcache lock held.. */ - write_lock_irq(&swapper_space.tree_lock); - if (page_count(page) == 2) - retval = 1; - write_unlock_irq(&swapper_space.tree_lock); - } + /* Subtract the 1 for the swap cache itself */ + count = p->swap_map[swp_offset(entry)] - 1; swap_info_put(p); } - return retval; + return count; } /* * We can use this swap cache entry directly * if there are no other references to it. - * - * Here "exclusive_swap_page()" does the real - * work, but we opportunistically check whether - * we need to get all the locks first.. */ int can_share_swap_page(struct page *page) { - int retval = 0; + int count; - if (!PageLocked(page)) - BUG(); - switch (page_count(page)) { - case 3: - if (!PagePrivate(page)) - break; - /* Fallthrough */ - case 2: - if (!PageSwapCache(page)) - break; - retval = exclusive_swap_page(page); - break; - case 1: - if (PageReserved(page)) - break; - retval = 1; - } - return retval; + BUG_ON(!PageLocked(page)); + count = page_mapcount(page); + if (count <= 1 && PageSwapCache(page)) + count += page_swapcount(page); + return count == 1; } /* @@ -529,9 +505,10 @@ static int unuse_mm(struct mm_struct *mm, if (!down_read_trylock(&mm->mmap_sem)) { /* - * Our reference to the page stops try_to_unmap_one from - * unmapping its ptes, so swapoff can make progress. + * Activate page so shrink_cache is unlikely to unmap its + * ptes while lock is dropped, so swapoff can make progress. */ + activate_page(page); unlock_page(page); down_read(&mm->mmap_sem); lock_page(page); -- cgit v0.10.2 From b4955ce3dd0818b56da532a16c9a4a3804a558ee Mon Sep 17 00:00:00 2001 From: Abhijit Karmarkar Date: Tue, 21 Jun 2005 17:15:13 -0700 Subject: [PATCH] msync: check pte dirty earlier It's common practice to msync a large address range regularly, in which often only a few ptes have actually been dirtied since the previous pass. sync_pte_range then goes much faster if it tests whether pte is dirty before locating and accessing each struct page cacheline; and it is hardly slowed by ptep_clear_flush_dirty repeating that test in the opposite case, when every pte actually is dirty. But beware, s390's pte_dirty always says false, since its dirty bit is kept in the storage key, located via the struct page address. So skip this optimization in its case: use a pte_maybe_dirty macro which just says true if page_test_and_clear_dirty is implemented. Signed-off-by: Abhijit Karmarkar Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 1f4ec7b..f405935 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -125,6 +125,9 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY #define page_test_and_clear_dirty(page) (0) +#define pte_maybe_dirty(pte) pte_dirty(pte) +#else +#define pte_maybe_dirty(pte) (1) #endif #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG diff --git a/mm/msync.c b/mm/msync.c index 090f426..d0f5a1b 100644 --- a/mm/msync.c +++ b/mm/msync.c @@ -34,6 +34,8 @@ static void sync_pte_range(struct vm_area_struct *vma, pmd_t *pmd, if (!pte_present(*pte)) continue; + if (!pte_maybe_dirty(*pte)) + continue; pfn = pte_pfn(*pte); if (!pfn_valid(pfn)) continue; -- cgit v0.10.2 From c0d62219a48bd91ec40fb254c930914dccc77ff1 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Tue, 21 Jun 2005 17:15:14 -0700 Subject: [PATCH] Kill stray newline OOM killer prints a stray newline. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 62b9509..2069207 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1314,7 +1314,7 @@ void show_free_areas(void) get_page_state(&ps); get_zone_counts(&active, &inactive, &free); - printk("\nFree pages: %11ukB (%ukB HighMem)\n", + printk("Free pages: %11ukB (%ukB HighMem)\n", K(nr_free_pages()), K(nr_free_highpages())); -- cgit v0.10.2 From 0f667ff5c0282f686b4f739e46353779b3cfa2f6 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 21 Jun 2005 17:15:14 -0700 Subject: [PATCH] 3c59x: remove superfluous vortex_debug test from boomerang_start_xmit() Remove the superfluous test of "if (vortex_debug > 3)" inside the "if (vortex_debug > 6)" clause early in boomerang_start_xmit. Signed-off-by: John W. Linville Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index b5e0760..80ec9aa 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2202,9 +2202,8 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) if (vortex_debug > 6) { printk(KERN_DEBUG "boomerang_start_xmit()\n"); - if (vortex_debug > 3) - printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", - dev->name, vp->cur_tx); + printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", + dev->name, vp->cur_tx); } if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) { -- cgit v0.10.2 From 2894801db1cea527885f7a8679e5a88fb7377d9c Mon Sep 17 00:00:00 2001 From: Coywolf Qi Hunt Date: Tue, 21 Jun 2005 17:15:15 -0700 Subject: [PATCH] kbuild: display compile version I am always trying to make sure I've booted the right kernel after a new install. Too paranoid maybe. But I guess there're other people like me. So let's make kbuild display the compile version number at the end to give us a hint. I know we may be booting vmlinux someday, but don't care about it for now. Signed-off-by: Coywolf Qi Hunt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile index aa7064a..43cd622 100644 --- a/arch/i386/boot/Makefile +++ b/arch/i386/boot/Makefile @@ -48,7 +48,7 @@ cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \ $(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \ $(obj)/vmlinux.bin $(obj)/tools/build FORCE $(call if_changed,image) - @echo 'Kernel: $@ is ready' + @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE $(call if_changed,objcopy) -- cgit v0.10.2 From 8680e22f296e75e5497edb660c59c6b4dcfbbd32 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Tue, 21 Jun 2005 17:15:16 -0700 Subject: [PATCH] VFS: memory leak in do_kern_mount() There is a memory leak during mount when CONFIG_SECURITY is enabled and mount options are specified. Signed-off-by: Gerald Schaefer Acked-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/super.c b/fs/super.c index 3a1b8ca..573bcc8 100644 --- a/fs/super.c +++ b/fs/super.c @@ -835,6 +835,7 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data) mnt->mnt_parent = mnt; mnt->mnt_namespace = current->namespace; up_write(&sb->s_umount); + free_secdata(secdata); put_filesystem(type); return mnt; out_sb: -- cgit v0.10.2 From da3caa204ca40c32dcb751ebead2a6835b83e8d1 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Tue, 21 Jun 2005 17:15:18 -0700 Subject: [PATCH] SELinux: memory leak in selinux_sb_copy_data() There is a memory leak during mount when SELinux is active and mount options are specified. Signed-off-by: Gerald Schaefer Acked-by: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index db845cb..87302a4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1945,6 +1945,7 @@ static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void } while (*in_end++); copy_page(in_save, nosec_save); + free_page((unsigned long)nosec_save); out: return rc; } -- cgit v0.10.2 From 5b37b700f7c491a9320f4e29472bbaf23dded8fd Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jun 2005 17:15:18 -0700 Subject: [PATCH] ppc32: Added support for new MPC8548 family of PowerQUICC III processors Added descriptions of the new MPC8548 family processors, e500 core and peripherals. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c index d44b7dc..01c2260 100644 --- a/arch/ppc/kernel/cputable.c +++ b/arch/ppc/kernel/cputable.c @@ -918,6 +918,20 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 4, }, + { /* e500v2 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x80210000, + .cpu_name = "e500v2", + /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_BIG_PHYS, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP | + PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_HAS_EFP_DOUBLE, + .icache_bsize = 32, + .dcache_bsize = 32, + .num_pmcs = 4, + }, #endif #if !CLASSIC_PPC { /* default match */ diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c index 1e658ef..b30c57d 100644 --- a/arch/ppc/syslib/mpc85xx_devices.c +++ b/arch/ppc/syslib/mpc85xx_devices.c @@ -40,6 +40,42 @@ static struct gianfar_platform_data mpc85xx_tsec2_pdata = { .phy_reg_addr = MPC85xx_ENET1_OFFSET, }; +static struct gianfar_platform_data mpc85xx_etsec1_pdata = { + .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | + FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | + FSL_GIANFAR_DEV_HAS_MULTI_INTR | + FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH, + .phy_reg_addr = MPC85xx_ENET1_OFFSET, +}; + +static struct gianfar_platform_data mpc85xx_etsec2_pdata = { + .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | + FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | + FSL_GIANFAR_DEV_HAS_MULTI_INTR | + FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH, + .phy_reg_addr = MPC85xx_ENET1_OFFSET, +}; + +static struct gianfar_platform_data mpc85xx_etsec3_pdata = { + .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | + FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | + FSL_GIANFAR_DEV_HAS_MULTI_INTR | + FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH, + .phy_reg_addr = MPC85xx_ENET1_OFFSET, +}; + +static struct gianfar_platform_data mpc85xx_etsec4_pdata = { + .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | + FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | + FSL_GIANFAR_DEV_HAS_MULTI_INTR | + FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH, + .phy_reg_addr = MPC85xx_ENET1_OFFSET, +}; + static struct gianfar_platform_data mpc85xx_fec_pdata = { .phy_reg_addr = MPC85xx_ENET1_OFFSET, }; @@ -48,6 +84,10 @@ static struct fsl_i2c_platform_data mpc85xx_fsl_i2c_pdata = { .device_flags = FSL_I2C_DEV_SEPARATE_DFSRR, }; +static struct fsl_i2c_platform_data mpc85xx_fsl_i2c2_pdata = { + .device_flags = FSL_I2C_DEV_SEPARATE_DFSRR, +}; + static struct plat_serial8250_port serial_platform_data[] = { [0] = { .mapbase = 0x4500, @@ -536,6 +576,151 @@ struct platform_device ppc_sys_platform_devices[] = { }, }, #endif /* CONFIG_CPM2 */ + [MPC85xx_eTSEC1] = { + .name = "fsl-gianfar", + .id = 1, + .dev.platform_data = &mpc85xx_etsec1_pdata, + .num_resources = 4, + .resource = (struct resource[]) { + { + .start = MPC85xx_ENET1_OFFSET, + .end = MPC85xx_ENET1_OFFSET + + MPC85xx_ENET1_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "tx", + .start = MPC85xx_IRQ_TSEC1_TX, + .end = MPC85xx_IRQ_TSEC1_TX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "rx", + .start = MPC85xx_IRQ_TSEC1_RX, + .end = MPC85xx_IRQ_TSEC1_RX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "error", + .start = MPC85xx_IRQ_TSEC1_ERROR, + .end = MPC85xx_IRQ_TSEC1_ERROR, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC85xx_eTSEC2] = { + .name = "fsl-gianfar", + .id = 2, + .dev.platform_data = &mpc85xx_etsec2_pdata, + .num_resources = 4, + .resource = (struct resource[]) { + { + .start = MPC85xx_ENET2_OFFSET, + .end = MPC85xx_ENET2_OFFSET + + MPC85xx_ENET2_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "tx", + .start = MPC85xx_IRQ_TSEC2_TX, + .end = MPC85xx_IRQ_TSEC2_TX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "rx", + .start = MPC85xx_IRQ_TSEC2_RX, + .end = MPC85xx_IRQ_TSEC2_RX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "error", + .start = MPC85xx_IRQ_TSEC2_ERROR, + .end = MPC85xx_IRQ_TSEC2_ERROR, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC85xx_eTSEC3] = { + .name = "fsl-gianfar", + .id = 3, + .dev.platform_data = &mpc85xx_etsec3_pdata, + .num_resources = 4, + .resource = (struct resource[]) { + { + .start = MPC85xx_ENET3_OFFSET, + .end = MPC85xx_ENET3_OFFSET + + MPC85xx_ENET3_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "tx", + .start = MPC85xx_IRQ_TSEC3_TX, + .end = MPC85xx_IRQ_TSEC3_TX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "rx", + .start = MPC85xx_IRQ_TSEC3_RX, + .end = MPC85xx_IRQ_TSEC3_RX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "error", + .start = MPC85xx_IRQ_TSEC3_ERROR, + .end = MPC85xx_IRQ_TSEC3_ERROR, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC85xx_eTSEC4] = { + .name = "fsl-gianfar", + .id = 4, + .dev.platform_data = &mpc85xx_etsec4_pdata, + .num_resources = 4, + .resource = (struct resource[]) { + { + .start = 0x27000, + .end = 0x27fff, + .flags = IORESOURCE_MEM, + }, + { + .name = "tx", + .start = MPC85xx_IRQ_TSEC4_TX, + .end = MPC85xx_IRQ_TSEC4_TX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "rx", + .start = MPC85xx_IRQ_TSEC4_RX, + .end = MPC85xx_IRQ_TSEC4_RX, + .flags = IORESOURCE_IRQ, + }, + { + .name = "error", + .start = MPC85xx_IRQ_TSEC4_ERROR, + .end = MPC85xx_IRQ_TSEC4_ERROR, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC85xx_IIC2] = { + .name = "fsl-i2c", + .id = 2, + .dev.platform_data = &mpc85xx_fsl_i2c2_pdata, + .num_resources = 2, + .resource = (struct resource[]) { + { + .start = 0x03100, + .end = 0x031ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MPC85xx_IRQ_IIC1, + .end = MPC85xx_IRQ_IIC1, + .flags = IORESOURCE_IRQ, + }, + }, + }, }; static int __init mach_mpc85xx_fixup(struct platform_device *pdev) diff --git a/arch/ppc/syslib/mpc85xx_sys.c b/arch/ppc/syslib/mpc85xx_sys.c index d806a92..6e3184a 100644 --- a/arch/ppc/syslib/mpc85xx_sys.c +++ b/arch/ppc/syslib/mpc85xx_sys.c @@ -110,6 +110,111 @@ struct ppc_sys_spec ppc_sys_specs[] = { MPC85xx_CPM_USB, }, }, + /* SVRs on 8548 rev1.0 matches for 8548/8547/8545 */ + { + .ppc_sys_name = "8548E", + .mask = 0xFFFF00F0, + .value = 0x80390010, + .num_devices = 13, + .device_list = (enum ppc_sys_devices[]) + { + MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3, + MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2, + MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, + MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2, + }, + }, + { + .ppc_sys_name = "8548", + .mask = 0xFFFF00F0, + .value = 0x80310010, + .num_devices = 12, + .device_list = (enum ppc_sys_devices[]) + { + MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3, + MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2, + MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, + MPC85xx_PERFMON, MPC85xx_DUART, + }, + }, + { + .ppc_sys_name = "8547E", + .mask = 0xFFFF00F0, + .value = 0x80390010, + .num_devices = 13, + .device_list = (enum ppc_sys_devices[]) + { + MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3, + MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2, + MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, + MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2, + }, + }, + { + .ppc_sys_name = "8547", + .mask = 0xFFFF00F0, + .value = 0x80310010, + .num_devices = 12, + .device_list = (enum ppc_sys_devices[]) + { + MPC85xx_eTSEC1, MPC85xx_eTSEC2, MPC85xx_eTSEC3, + MPC85xx_eTSEC4, MPC85xx_IIC1, MPC85xx_IIC2, + MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, + MPC85xx_PERFMON, MPC85xx_DUART, + }, + }, + { + .ppc_sys_name = "8545E", + .mask = 0xFFFF00F0, + .value = 0x80390010, + .num_devices = 11, + .device_list = (enum ppc_sys_devices[]) + { + MPC85xx_eTSEC1, MPC85xx_eTSEC2, + MPC85xx_IIC1, MPC85xx_IIC2, + MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, + MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2, + }, + }, + { + .ppc_sys_name = "8545", + .mask = 0xFFFF00F0, + .value = 0x80310010, + .num_devices = 10, + .device_list = (enum ppc_sys_devices[]) + { + MPC85xx_eTSEC1, MPC85xx_eTSEC2, + MPC85xx_IIC1, MPC85xx_IIC2, + MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, + MPC85xx_PERFMON, MPC85xx_DUART, + }, + }, + { + .ppc_sys_name = "8543E", + .mask = 0xFFFF00F0, + .value = 0x803A0010, + .num_devices = 11, + .device_list = (enum ppc_sys_devices[]) + { + MPC85xx_eTSEC1, MPC85xx_eTSEC2, + MPC85xx_IIC1, MPC85xx_IIC2, + MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, + MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2, + }, + }, + { + .ppc_sys_name = "8543", + .mask = 0xFFFF00F0, + .value = 0x80320010, + .num_devices = 10, + .device_list = (enum ppc_sys_devices[]) + { + MPC85xx_eTSEC1, MPC85xx_eTSEC2, + MPC85xx_IIC1, MPC85xx_IIC2, + MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3, + MPC85xx_PERFMON, MPC85xx_DUART, + }, + }, { /* default match */ .ppc_sys_name = "", .mask = 0x00000000, diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h index 06b86be..434fc51 100644 --- a/include/asm-ppc/irq.h +++ b/include/asm-ppc/irq.h @@ -223,9 +223,15 @@ static __inline__ int irq_canonicalize(int irq) #define MPC85xx_IRQ_RIO_RX (12 + MPC85xx_OPENPIC_IRQ_OFFSET) #define MPC85xx_IRQ_TSEC1_TX (13 + MPC85xx_OPENPIC_IRQ_OFFSET) #define MPC85xx_IRQ_TSEC1_RX (14 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC3_TX (15 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC3_RX (16 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC3_ERROR (17 + MPC85xx_OPENPIC_IRQ_OFFSET) #define MPC85xx_IRQ_TSEC1_ERROR (18 + MPC85xx_OPENPIC_IRQ_OFFSET) #define MPC85xx_IRQ_TSEC2_TX (19 + MPC85xx_OPENPIC_IRQ_OFFSET) #define MPC85xx_IRQ_TSEC2_RX (20 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC4_TX (21 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC4_RX (22 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_TSEC4_ERROR (23 + MPC85xx_OPENPIC_IRQ_OFFSET) #define MPC85xx_IRQ_TSEC2_ERROR (24 + MPC85xx_OPENPIC_IRQ_OFFSET) #define MPC85xx_IRQ_FEC (25 + MPC85xx_OPENPIC_IRQ_OFFSET) #define MPC85xx_IRQ_DUART (26 + MPC85xx_OPENPIC_IRQ_OFFSET) diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h index 22713e3..51b61d3 100644 --- a/include/asm-ppc/mpc85xx.h +++ b/include/asm-ppc/mpc85xx.h @@ -74,7 +74,7 @@ extern unsigned char __res[]; #define MPC85xx_GUTS_OFFSET (0xe0000) #define MPC85xx_GUTS_SIZE (0x01000) #define MPC85xx_IIC1_OFFSET (0x03000) -#define MPC85xx_IIC1_SIZE (0x01000) +#define MPC85xx_IIC1_SIZE (0x00100) #define MPC85xx_OPENPIC_OFFSET (0x40000) #define MPC85xx_OPENPIC_SIZE (0x40000) #define MPC85xx_PCI1_OFFSET (0x08000) @@ -127,6 +127,11 @@ enum ppc_sys_devices { MPC85xx_CPM_MCC2, MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2, + MPC85xx_eTSEC1, + MPC85xx_eTSEC2, + MPC85xx_eTSEC3, + MPC85xx_eTSEC4, + MPC85xx_IIC2, }; #endif /* CONFIG_85xx */ diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index faaff4c..70f54af 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -51,6 +51,7 @@ struct gianfar_platform_data { /* board specific information */ u32 board_flags; + u32 phy_flags; u32 phyid; u32 interruptPHY; u8 mac_addr[6]; @@ -61,9 +62,14 @@ struct gianfar_platform_data { #define FSL_GIANFAR_DEV_HAS_COALESCE 0x00000002 #define FSL_GIANFAR_DEV_HAS_RMON 0x00000004 #define FSL_GIANFAR_DEV_HAS_MULTI_INTR 0x00000008 +#define FSL_GIANFAR_DEV_HAS_CSUM 0x00000010 +#define FSL_GIANFAR_DEV_HAS_VLAN 0x00000020 +#define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH 0x00000040 +#define FSL_GIANFAR_DEV_HAS_PADDING 0x00000080 /* Flags in gianfar_platform_data */ -#define FSL_GIANFAR_BRD_HAS_PHY_INTR 0x00000001 /* if not set use a timer */ +#define FSL_GIANFAR_BRD_HAS_PHY_INTR 0x00000001 /* set or use a timer */ +#define FSL_GIANFAR_BRD_IS_REDUCED 0x00000002 /* Set if RGMII, RMII */ struct fsl_i2c_platform_data { /* device specific information */ -- cgit v0.10.2 From c91999bba3ae8b21d4a965f19bf127bac3e5f7f2 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jun 2005 17:15:19 -0700 Subject: [PATCH] ppc32: Added preliminary support for the MPC8548 CDS board Adds support for using the MPC8548 processor on the CDS reference board. Currently all the major busses (PCI, PCI-X, PCI-Express, sRIO) and eTSEC3 and eTSEC4 are not supported. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/configs/mpc8548_cds_defconfig b/arch/ppc/configs/mpc8548_cds_defconfig new file mode 100644 index 0000000..abe034f --- /dev/null +++ b/arch/ppc/configs/mpc8548_cds_defconfig @@ -0,0 +1,659 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc4 +# Tue May 24 22:36:27 2005 +# +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Processor +# +# CONFIG_6xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +CONFIG_E500=y +CONFIG_BOOKE=y +CONFIG_FSL_BOOKE=y +# CONFIG_PHYS_64BIT is not set +CONFIG_SPE=y +CONFIG_MATH_EMULATION=y +# CONFIG_CPU_FREQ is not set +# CONFIG_PM is not set +CONFIG_85xx=y +CONFIG_PPC_INDIRECT_PCI_BE=y + +# +# Freescale 85xx options +# +# CONFIG_MPC8540_ADS is not set +CONFIG_MPC8548_CDS=y +# CONFIG_MPC8555_CDS is not set +# CONFIG_MPC8560_ADS is not set +# CONFIG_SBC8560 is not set +# CONFIG_STX_GP3 is not set +CONFIG_MPC8548=y + +# +# Platform options +# +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_HIGHMEM is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_CMDLINE_BOOL is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_LBD is not set +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Macintosh device drivers +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y + +# +# Ethernet (1000 Mbit) +# +CONFIG_GIANFAR=y +CONFIG_GFAR_NAPI=y + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ISA is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# diff --git a/arch/ppc/platforms/85xx/Kconfig b/arch/ppc/platforms/85xx/Kconfig index ff92e38..c5bc282 100644 --- a/arch/ppc/platforms/85xx/Kconfig +++ b/arch/ppc/platforms/85xx/Kconfig @@ -21,6 +21,11 @@ config MPC8540_ADS help This option enables support for the MPC 8540 ADS evaluation board. +config MPC8548_CDS + bool "Freescale MPC8548 CDS" + help + This option enablese support for the MPC8548 CDS evaluation board. + config MPC8555_CDS bool "Freescale MPC8555 CDS" help @@ -53,6 +58,11 @@ config MPC8540 depends on MPC8540_ADS default y +config MPC8548 + bool + depends on MPC8548_CDS + default y + config MPC8555 bool depends on MPC8555_CDS diff --git a/arch/ppc/platforms/85xx/Makefile b/arch/ppc/platforms/85xx/Makefile index 854fbd2..efdf813 100644 --- a/arch/ppc/platforms/85xx/Makefile +++ b/arch/ppc/platforms/85xx/Makefile @@ -2,6 +2,7 @@ # Makefile for the PowerPC 85xx linux kernel. # obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads_common.o mpc8540_ads.o +obj-$(CONFIG_MPC8548_CDS) += mpc85xx_cds_common.o obj-$(CONFIG_MPC8555_CDS) += mpc85xx_cds_common.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads_common.o mpc8560_ads.o obj-$(CONFIG_SBC8560) += sbc85xx.o sbc8560.o diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index e7cfa49..2d04bf5 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -480,21 +480,47 @@ mpc85xx_cds_setup_arch(void) /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); - pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 0; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 0; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); - pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 1; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 1; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + } + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_eTSEC1); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 0; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + } + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_eTSEC2); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 1; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + } + ppc_sys_device_remove(MPC85xx_eTSEC3); + ppc_sys_device_remove(MPC85xx_eTSEC4); #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index 96acf85..6e7ecbc 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_83xx) += ipic.o ppc83xx_setup.o ppc_sys.o \ ifeq ($(CONFIG_83xx),y) obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o endif +obj-$(CONFIG_MPC8548_CDS) += todc_time.o obj-$(CONFIG_MPC8555_CDS) += todc_time.o obj-$(CONFIG_PPC_MPC52xx) += mpc52xx_setup.o mpc52xx_pic.o \ mpc52xx_sys.o mpc52xx_devices.o ppc_sys.o diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c index f3277f4..455473f 100644 --- a/arch/ppc/syslib/ppc85xx_setup.c +++ b/arch/ppc/syslib/ppc85xx_setup.c @@ -133,7 +133,7 @@ mpc85xx_halt(void) #ifdef CONFIG_PCI -#if defined(CONFIG_MPC8555_CDS) +#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS) extern void mpc85xx_cds_enable_via(struct pci_controller *hose); extern void mpc85xx_cds_fixup_via(struct pci_controller *hose); #endif @@ -308,14 +308,14 @@ mpc85xx_setup_hose(void) ppc_md.pci_exclude_device = mpc85xx_exclude_device; -#if defined(CONFIG_MPC8555_CDS) +#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS) /* Pre pciauto_bus_scan VIA init */ mpc85xx_cds_enable_via(hose_a); #endif hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); -#if defined(CONFIG_MPC8555_CDS) +#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS) /* Post pciauto_bus_scan VIA fixup */ mpc85xx_cds_fixup_via(hose_a); #endif diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h index 51b61d3..95cc22d 100644 --- a/include/asm-ppc/mpc85xx.h +++ b/include/asm-ppc/mpc85xx.h @@ -25,7 +25,7 @@ #ifdef CONFIG_MPC8540_ADS #include #endif -#ifdef CONFIG_MPC8555_CDS +#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS) #include #endif #ifdef CONFIG_MPC8560_ADS -- cgit v0.10.2 From c93fcff6952068d484f2f7dae187037f46235647 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jun 2005 17:15:20 -0700 Subject: [PATCH] ppc32: Removed dependency on CONFIG_CPM2 for building mpc85xx_device.c Previously we needed CONFIG_CPM2 enabled to get the proper IRQ ifdef's for CPM interrupts. Recent changes have caused that to be no longer necessary. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c index b30c57d..8af322d 100644 --- a/arch/ppc/syslib/mpc85xx_devices.c +++ b/arch/ppc/syslib/mpc85xx_devices.c @@ -321,7 +321,6 @@ struct platform_device ppc_sys_platform_devices[] = { }, }, }, -#ifdef CONFIG_CPM2 [MPC85xx_CPM_FCC1] = { .name = "fsl-cpm-fcc", .id = 1, @@ -575,7 +574,6 @@ struct platform_device ppc_sys_platform_devices[] = { }, }, }, -#endif /* CONFIG_CPM2 */ [MPC85xx_eTSEC1] = { .name = "fsl-gianfar", .id = 1, -- cgit v0.10.2 From b264c3527930ca4812fefc505fde9ad99d8a0117 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jun 2005 17:15:21 -0700 Subject: [PATCH] ppc32: Converted MPC10X bridge to use platform devices instead of OCP Converted the MPC10x bridge support (used by MPC10x and 8240/1/5) to used the standard platform device model. Signed-off-by: Matt McClintock Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 54ce6da..10162b1 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -826,11 +826,6 @@ config MPC10X_BRIDGE depends on PCORE || POWERPMC250 || LOPEC || SANDPOINT default y -config FSL_OCP - bool - depends on MPC10X_BRIDGE - default y - config MPC10X_OPENPIC bool depends on POWERPMC250 || LOPEC || SANDPOINT diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 5c20266..c344c66 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -41,7 +41,7 @@ #include #include -#if defined(CONFIG_85xx) || defined(CONFIG_83xx) +#if defined(CONFIG_85xx) || defined(CONFIG_83xx) || defined(CONFIG_MPC10X_BRIDGE) #include #endif @@ -249,7 +249,7 @@ int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "bogomips\t: %lu.%02lu\n", lpj / (500000/HZ), (lpj / (5000/HZ)) % 100); -#if defined(CONFIG_85xx) || defined(CONFIG_83xx) +#if defined(CONFIG_85xx) || defined(CONFIG_83xx) || defined(CONFIG_MPC10X_BRIDGE) if (cur_ppc_sys_spec->ppc_sys_name) seq_printf(m, "chipset\t\t: %s\n", cur_ppc_sys_spec->ppc_sys_name); diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index 6e7ecbc..dec5bf4 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -92,7 +92,7 @@ ifeq ($(CONFIG_SERIAL_MPSC_CONSOLE),y) obj-$(CONFIG_SERIAL_TEXT_DEBUG) += mv64x60_dbg.o endif obj-$(CONFIG_BOOTX_TEXT) += btext.o -obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o indirect_pci.o +obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o indirect_pci.o ppc_sys.o obj-$(CONFIG_MPC10X_OPENPIC) += open_pic.o obj-$(CONFIG_40x) += dcr.o obj-$(CONFIG_BOOKE) += dcr.o diff --git a/arch/ppc/syslib/mpc10x_common.c b/arch/ppc/syslib/mpc10x_common.c index fd93adf..0130aeb 100644 --- a/arch/ppc/syslib/mpc10x_common.c +++ b/arch/ppc/syslib/mpc10x_common.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include #include @@ -30,16 +33,7 @@ #include #include #include -#include - -/* The OCP structure is fixed by code below, before OCP initialises. - paddr depends on where the board places the EUMB. - - fixed in mpc10x_bridge_init(). - irq depends on two things: - > does the board use the EPIC at all? (PCORE does not). - > is the EPIC in serial or parallel mode? - - fixed in mpc10x_set_openpic(). -*/ +#include #ifdef CONFIG_MPC10X_OPENPIC #ifdef CONFIG_EPIC_SERIAL_MODE @@ -51,34 +45,127 @@ #define MPC10X_DMA0_IRQ (EPIC_IRQ_BASE + 1 + NUM_8259_INTERRUPTS) #define MPC10X_DMA1_IRQ (EPIC_IRQ_BASE + 2 + NUM_8259_INTERRUPTS) #else -#define MPC10X_I2C_IRQ OCP_IRQ_NA -#define MPC10X_DMA0_IRQ OCP_IRQ_NA -#define MPC10X_DMA1_IRQ OCP_IRQ_NA +#define MPC10X_I2C_IRQ -1 +#define MPC10X_DMA0_IRQ -1 +#define MPC10X_DMA1_IRQ -1 #endif - -struct ocp_def core_ocp[] = { - { .vendor = OCP_VENDOR_INVALID - } +static struct fsl_i2c_platform_data mpc10x_i2c_pdata = { + .device_flags = 0, }; -static struct ocp_fs_i2c_data mpc10x_i2c_data = { - .flags = 0 +static struct plat_serial8250_port serial_platform_data[] = { + { }, }; -static struct ocp_def mpc10x_i2c_ocp = { - .vendor = OCP_VENDOR_MOTOROLA, - .function = OCP_FUNC_IIC, - .index = 0, - .additions = &mpc10x_i2c_data + +struct platform_device ppc_sys_platform_devices[] = { + [MPC10X_IIC1] = { + .name = "fsl-i2c", + .id = 1, + .dev.platform_data = &mpc10x_i2c_pdata, + .num_resources = 2, + .resource = (struct resource[]) { + { + .start = MPC10X_EUMB_I2C_OFFSET, + .end = MPC10X_EUMB_I2C_OFFSET + + MPC10X_EUMB_I2C_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .flags = IORESOURCE_IRQ + }, + }, + }, + [MPC10X_DMA0] = { + .name = "fsl-dma", + .id = 0, + .num_resources = 2, + .resource = (struct resource[]) { + { + .start = MPC10X_EUMB_DMA_OFFSET + 0x10, + .end = MPC10X_EUMB_DMA_OFFSET + 0x1f, + .flags = IORESOURCE_MEM, + }, + { + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC10X_DMA1] = { + .name = "fsl-dma", + .id = 1, + .num_resources = 2, + .resource = (struct resource[]) { + { + .start = MPC10X_EUMB_DMA_OFFSET + 0x20, + .end = MPC10X_EUMB_DMA_OFFSET + 0x2f, + .flags = IORESOURCE_MEM, + }, + { + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC10X_DMA1] = { + .name = "fsl-dma", + .id = 1, + .num_resources = 2, + .resource = (struct resource[]) { + { + .start = MPC10X_EUMB_DMA_OFFSET + 0x20, + .end = MPC10X_EUMB_DMA_OFFSET + 0x2f, + .flags = IORESOURCE_MEM, + }, + { + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC10X_DUART] = { + .name = "serial8250", + .id = 0, + .dev.platform_data = serial_platform_data, + }, }; -static struct ocp_def mpc10x_dma_ocp[2] = { -{ .vendor = OCP_VENDOR_MOTOROLA, - .function = OCP_FUNC_DMA, - .index = 0 }, -{ .vendor = OCP_VENDOR_MOTOROLA, - .function = OCP_FUNC_DMA, - .index = 1 } +/* We use the PCI ID to match on */ +struct ppc_sys_spec *cur_ppc_sys_spec; +struct ppc_sys_spec ppc_sys_specs[] = { + { + .ppc_sys_name = "8245", + .mask = 0xFFFFFFFF, + .value = MPC10X_BRIDGE_8245, + .num_devices = 4, + .device_list = (enum ppc_sys_devices[]) + { + MPC10X_IIC1, MPC10X_DMA0, MPC10X_DMA1, MPC10X_DUART, + }, + }, + { + .ppc_sys_name = "8240", + .mask = 0xFFFFFFFF, + .value = MPC10X_BRIDGE_8240, + .num_devices = 3, + .device_list = (enum ppc_sys_devices[]) + { + MPC10X_IIC1, MPC10X_DMA0, MPC10X_DMA1, + }, + }, + { + .ppc_sys_name = "107", + .mask = 0xFFFFFFFF, + .value = MPC10X_BRIDGE_107, + .num_devices = 3, + .device_list = (enum ppc_sys_devices[]) + { + MPC10X_IIC1, MPC10X_DMA0, MPC10X_DMA1, + }, + }, + { /* default match */ + .ppc_sys_name = "", + .mask = 0x00000000, + .value = 0x00000000, + }, }; /* Set resources to match bridge memory map */ @@ -132,7 +219,7 @@ mpc10x_bridge_init(struct pci_controller *hose, uint new_map, uint phys_eumb_base) { - int host_bridge, picr1, picr1_bit; + int host_bridge, picr1, picr1_bit, i; ulong pci_config_addr, pci_config_data; u_char pir, byte; @@ -273,7 +360,7 @@ mpc10x_bridge_init(struct pci_controller *hose, printk("Host bridge in Agent mode\n"); /* Read or Set LMBAR & PCSRBAR? */ } - + /* Set base addr of the 8240/107 EUMB. */ early_write_config_dword(hose, 0, @@ -287,17 +374,6 @@ mpc10x_bridge_init(struct pci_controller *hose, ioremap(phys_eumb_base + MPC10X_EUMB_EPIC_OFFSET, MPC10X_EUMB_EPIC_SIZE); #endif - mpc10x_i2c_ocp.paddr = phys_eumb_base + MPC10X_EUMB_I2C_OFFSET; - mpc10x_i2c_ocp.irq = MPC10X_I2C_IRQ; - ocp_add_one_device(&mpc10x_i2c_ocp); - mpc10x_dma_ocp[0].paddr = phys_eumb_base + - MPC10X_EUMB_DMA_OFFSET + 0x100; - mpc10x_dma_ocp[0].irq = MPC10X_DMA0_IRQ; - ocp_add_one_device(&mpc10x_dma_ocp[0]); - mpc10x_dma_ocp[1].paddr = phys_eumb_base + - MPC10X_EUMB_DMA_OFFSET + 0x200; - mpc10x_dma_ocp[1].irq = MPC10X_DMA1_IRQ; - ocp_add_one_device(&mpc10x_dma_ocp[1]); } #ifdef CONFIG_MPC10X_STORE_GATHERING @@ -306,6 +382,23 @@ mpc10x_bridge_init(struct pci_controller *hose, mpc10x_disable_store_gathering(hose); #endif + /* setup platform devices for MPC10x bridges */ + identify_ppc_sys_by_id (host_bridge); + + for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) { + unsigned int dev_id = cur_ppc_sys_spec->device_list[i]; + ppc_sys_fixup_mem_resource(&ppc_sys_platform_devices[dev_id], + phys_eumb_base); + } + + /* IRQ's are determined at runtime */ + ppc_sys_platform_devices[MPC10X_IIC1].resource[1].start = MPC10X_I2C_IRQ; + ppc_sys_platform_devices[MPC10X_IIC1].resource[1].end = MPC10X_I2C_IRQ; + ppc_sys_platform_devices[MPC10X_DMA0].resource[1].start = MPC10X_DMA0_IRQ; + ppc_sys_platform_devices[MPC10X_DMA0].resource[1].end = MPC10X_DMA0_IRQ; + ppc_sys_platform_devices[MPC10X_DMA1].resource[1].start = MPC10X_DMA1_IRQ; + ppc_sys_platform_devices[MPC10X_DMA1].resource[1].end = MPC10X_DMA1_IRQ; + /* * 8240 erratum 26, 8241/8245 erratum 29, 107 erratum 23: speculative * PCI reads may return stale data so turn off. @@ -330,7 +423,7 @@ mpc10x_bridge_init(struct pci_controller *hose, * 8245 (Rev 2., dated 10/2003) says PICR2[0] is reserverd. */ if (host_bridge == MPC10X_BRIDGE_8245) { - ulong picr2; + u32 picr2; early_read_config_dword(hose, 0, PCI_DEVFN(0,0), MPC10X_CFG_PICR2_REG, &picr2); diff --git a/include/asm-ppc/mpc10x.h b/include/asm-ppc/mpc10x.h index d8e7e2d..f5196a4 100644 --- a/include/asm-ppc/mpc10x.h +++ b/include/asm-ppc/mpc10x.h @@ -159,6 +159,12 @@ extern unsigned long ioremap_base; #define MPC10X_MAPA_EUMB_BASE (ioremap_base - MPC10X_EUMB_SIZE) #define MPC10X_MAPB_EUMB_BASE MPC10X_MAPA_EUMB_BASE +enum ppc_sys_devices { + MPC10X_IIC1, + MPC10X_DMA0, + MPC10X_DMA1, + MPC10X_DUART, +}; int mpc10x_bridge_init(struct pci_controller *hose, uint current_map, diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h index 24b991c..8ea6245 100644 --- a/include/asm-ppc/ppc_sys.h +++ b/include/asm-ppc/ppc_sys.h @@ -27,6 +27,8 @@ #include #elif defined(CONFIG_PPC_MPC52xx) #include +#elif defined(CONFIG_MPC10X_BRIDGE) +#include #else #error "need definition of ppc_sys_devices" #endif -- cgit v0.10.2 From a1604f9121ee97b27d5ce308ddd4b70c3a220279 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Tue, 21 Jun 2005 17:15:22 -0700 Subject: [PATCH] cpm_uart: Route SCC2 pins for the STx GP3 board Adds SCC2 pin routing specific to the GP3 board. Signed-off-by: Matt Porter Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index b422c3a..c4c8f4b 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -134,12 +134,21 @@ void scc1_lineif(struct uart_cpm_port *pinfo) void scc2_lineif(struct uart_cpm_port *pinfo) { + /* + * STx GP3 uses the SCC2 secondary option pin assignment + * which this driver doesn't account for in the static + * pin assignments. This kind of board specific info + * really has to get out of the driver so boards can + * be supported in a sane fashion. + */ +#ifndef CONFIG_STX_GP3 volatile iop_cpm2_t *io = &cpm2_immr->im_ioport; io->iop_pparb |= 0x008b0000; io->iop_pdirb |= 0x00880000; io->iop_psorb |= 0x00880000; io->iop_pdirb &= ~0x00030000; io->iop_psorb &= ~0x00030000; +#endif cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff; cpm2_immr->im_cpmux.cmx_scr |= 0x00090000; pinfo->brg = 2; -- cgit v0.10.2 From 1e5aa8c86571deea5d8e8462fedcf610e21af717 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Tue, 21 Jun 2005 17:15:22 -0700 Subject: [PATCH] ppc32: fix CONFIG_TASK_SIZE handling on 40x This patch is virtually identical to my previous 44x one. It removes 0x8000'0000 TASK_SIZE hardcoded assumption from head_4xx.S. Signed-off-by: Eugene Surovegin Signed-off-by: Matt Porter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S index 6f5d380..23fb518 100644 --- a/arch/ppc/kernel/head_4xx.S +++ b/arch/ppc/kernel/head_4xx.S @@ -291,8 +291,9 @@ label: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - andis. r11, r10, 0x8000 - beq 3f + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l li r9, 0 @@ -479,8 +480,9 @@ label: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - andis. r11, r10, 0x8000 - beq 3f + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l li r9, 0 @@ -578,8 +580,9 @@ label: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - andis. r11, r10, 0x8000 - beq 3f + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l li r9, 0 -- cgit v0.10.2 From 682afbbd1456e9e7b64f482eb05676b933173cdf Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jun 2005 17:15:23 -0700 Subject: [PATCH] ppc32: Add support for MPC8245 8250 serial ports on Sandpoint Added platform device initialization for the two 8250 style UARTs that exist on the MPC8245. Additionally, updated the Sandpoint code to enable one of these UARTs if an MPC8245 is connected to it. Signed-off-by: Matt McClintock Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c index 531bfa0..70e58f4 100644 --- a/arch/ppc/platforms/sandpoint.c +++ b/arch/ppc/platforms/sandpoint.c @@ -81,6 +81,7 @@ #include #include /* for linux/serial_core.h */ #include +#include #include #include @@ -99,6 +100,7 @@ #include #include #include +#include #include "sandpoint.h" @@ -305,6 +307,24 @@ sandpoint_setup_arch(void) /* Lookup PCI host bridges */ sandpoint_find_bridges(); + if (strncmp (cur_ppc_sys_spec->ppc_sys_name, "8245", 4) == 0) + { + bd_t *bp = (bd_t *)__res; + struct plat_serial8250_port *pdata; + pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(MPC10X_DUART); + + if (pdata) + { + pdata[0].uartclk = bp->bi_busfreq; + pdata[0].membase = ioremap(pdata[0].mapbase, 0x100); + + /* this disables the 2nd serial port on the DUART + * since the sandpoint does not have it connected */ + pdata[1].uartclk = 0; + pdata[1].irq = 0; + pdata[1].mapbase = 0; + } + printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n"); printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n"); diff --git a/arch/ppc/syslib/mpc10x_common.c b/arch/ppc/syslib/mpc10x_common.c index 0130aeb..8fc5f41 100644 --- a/arch/ppc/syslib/mpc10x_common.c +++ b/arch/ppc/syslib/mpc10x_common.c @@ -44,10 +44,12 @@ #define MPC10X_I2C_IRQ (EPIC_IRQ_BASE + NUM_8259_INTERRUPTS) #define MPC10X_DMA0_IRQ (EPIC_IRQ_BASE + 1 + NUM_8259_INTERRUPTS) #define MPC10X_DMA1_IRQ (EPIC_IRQ_BASE + 2 + NUM_8259_INTERRUPTS) +#define MPC10X_UART0_IRQ (EPIC_IRQ_BASE + 4 + NUM_8259_INTERRUPTS) #else #define MPC10X_I2C_IRQ -1 #define MPC10X_DMA0_IRQ -1 #define MPC10X_DMA1_IRQ -1 +#define MPC10X_UART0_IRQ -1 #endif static struct fsl_i2c_platform_data mpc10x_i2c_pdata = { @@ -55,6 +57,16 @@ static struct fsl_i2c_platform_data mpc10x_i2c_pdata = { }; static struct plat_serial8250_port serial_platform_data[] = { + [0] = { + .mapbase = 0x4500, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + }, + [1] = { + .mapbase = 0x4600, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + }, { }, }; @@ -399,6 +411,12 @@ mpc10x_bridge_init(struct pci_controller *hose, ppc_sys_platform_devices[MPC10X_DMA1].resource[1].start = MPC10X_DMA1_IRQ; ppc_sys_platform_devices[MPC10X_DMA1].resource[1].end = MPC10X_DMA1_IRQ; + serial_platform_data[0].mapbase += phys_eumb_base; + serial_platform_data[0].irq = MPC10X_UART0_IRQ; + + serial_platform_data[1].mapbase += phys_eumb_base; + serial_platform_data[1].irq = MPC10X_UART0_IRQ + 1; + /* * 8240 erratum 26, 8241/8245 erratum 29, 107 erratum 23: speculative * PCI reads may return stale data so turn off. @@ -597,6 +615,8 @@ void __init mpc10x_set_openpic(void) openpic_set_sources(EPIC_IRQ_BASE, 3, OpenPIC_Addr + 0x11020); /* Skip reserved space and map Message Unit Interrupt (I2O) */ openpic_set_sources(EPIC_IRQ_BASE + 3, 1, OpenPIC_Addr + 0x110C0); + /* Skip reserved space and map Serial Interupts */ + openpic_set_sources(EPIC_IRQ_BASE + 4, 2, OpenPIC_Addr + 0x11120); openpic_init(NUM_8259_INTERRUPTS); } -- cgit v0.10.2 From eee4146ab908188e556641f1cd7a10e894d10edb Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Tue, 21 Jun 2005 17:15:24 -0700 Subject: [PATCH] ppc32: remove orphaned ppc4xx_kgdb.c Removes ppc4xx_kgdb.c which is no longer being used. Pointed out by Andrei Konovalov. Signed-off-by: Matt Porter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/syslib/ppc4xx_kgdb.c b/arch/ppc/syslib/ppc4xx_kgdb.c deleted file mode 100644 index fe8668b..0000000 --- a/arch/ppc/syslib/ppc4xx_kgdb.c +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include -#include - - - -#define LSR_DR 0x01 /* Data ready */ -#define LSR_OE 0x02 /* Overrun */ -#define LSR_PE 0x04 /* Parity error */ -#define LSR_FE 0x08 /* Framing error */ -#define LSR_BI 0x10 /* Break */ -#define LSR_THRE 0x20 /* Xmit holding register empty */ -#define LSR_TEMT 0x40 /* Xmitter empty */ -#define LSR_ERR 0x80 /* Error */ - -#include - -extern struct NS16550* COM_PORTS[]; -#ifndef NULL -#define NULL 0x00 -#endif - -static volatile struct NS16550 *kgdb_debugport = NULL; - -volatile struct NS16550 * -NS16550_init(int chan) -{ - volatile struct NS16550 *com_port; - int quot; -#ifdef BASE_BAUD - quot = BASE_BAUD / 9600; -#else - quot = 0x000c; /* 0xc = 9600 baud (on a pc) */ -#endif - - com_port = (struct NS16550 *) COM_PORTS[chan]; - - com_port->lcr = 0x00; - com_port->ier = 0xFF; - com_port->ier = 0x00; - com_port->lcr = com_port->lcr | 0x80; /* Access baud rate */ - com_port->dll = ( quot & 0x00ff ); /* 0xc = 9600 baud */ - com_port->dlm = ( quot & 0xff00 ) >> 8; - com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */ - com_port->mcr = 0x00; /* RTS/DTR */ - com_port->fcr = 0x07; /* Clear & enable FIFOs */ - - return( com_port ); -} - - -void -NS16550_putc(volatile struct NS16550 *com_port, unsigned char c) -{ - while ((com_port->lsr & LSR_THRE) == 0) - ; - com_port->thr = c; - return; -} - -unsigned char -NS16550_getc(volatile struct NS16550 *com_port) -{ - while ((com_port->lsr & LSR_DR) == 0) - ; - return (com_port->rbr); -} - -unsigned char -NS16550_tstc(volatile struct NS16550 *com_port) -{ - return ((com_port->lsr & LSR_DR) != 0); -} - - -#if defined(CONFIG_KGDB_TTYS0) -#define KGDB_PORT 0 -#elif defined(CONFIG_KGDB_TTYS1) -#define KGDB_PORT 1 -#elif defined(CONFIG_KGDB_TTYS2) -#define KGDB_PORT 2 -#elif defined(CONFIG_KGDB_TTYS3) -#define KGDB_PORT 3 -#else -#error "invalid kgdb_tty port" -#endif - -void putDebugChar( unsigned char c ) -{ - if ( kgdb_debugport == NULL ) - kgdb_debugport = NS16550_init(KGDB_PORT); - NS16550_putc( kgdb_debugport, c ); -} - -int getDebugChar( void ) -{ - if (kgdb_debugport == NULL) - kgdb_debugport = NS16550_init(KGDB_PORT); - - return(NS16550_getc(kgdb_debugport)); -} - -void kgdb_interruptible(int enable) -{ - return; -} - -void putDebugString(char* str) -{ - while (*str != '\0') { - putDebugChar(*str); - str++; - } - putDebugChar('\r'); - return; -} - -void -kgdb_map_scc(void) -{ - printk("kgdb init \n"); - kgdb_debugport = NS16550_init(KGDB_PORT); -} -- cgit v0.10.2 From 65145e060b1c933ebc4215c3b493f586e08a1d5c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jun 2005 17:15:25 -0700 Subject: [PATCH] ppc32: Added support for all MPC8548 internal interrupts The MPC8548 has 48 internal interrupts and 12 external interrupts. The previous generation PowerQUICC III devices only had 32 internal and 12 external interrupts on the primary interrupt controller. Expanded the number of internal interrupts to 48 for all PowerQUICC III processors and moved the interrupt numbers for the external after the 48 internal interrupt lines, rather than putting the 12 new internal interrupts at the end and ifdef'ng the whole mess. As parted of this created a macro which represents the internal interrupt senses since they are the same on all PQ3 processors. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c index ba9f9f5..3039762 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c @@ -59,40 +59,8 @@ extern unsigned long total_memory; /* in mm/init */ unsigned char __res[sizeof (bd_t)]; /* Internal interrupts are all Level Sensitive, and Positive Polarity */ - static u_char mpc85xx_ads_openpic_initsenses[] __initdata = { - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ + MPC85XX_INTERNAL_IRQ_SENSES, 0x0, /* External 0: */ #if defined(CONFIG_PCI) (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI slot 0 */ @@ -159,7 +127,7 @@ mpc85xx_ads_init_IRQ(void) /* Skip reserved space and internal sources */ openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200); /* Map PIC IRQs 0-11 */ - openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000); + openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000); /* we let openpic interrupts starting from an offset, to * leave space for cascading interrupts underneath. diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 2d04bf5..bee6633 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -73,40 +73,8 @@ static int cds_pci_slot = 2; static volatile u8 * cadmus; /* Internal interrupts are all Level Sensitive, and Positive Polarity */ - static u_char mpc85xx_cds_openpic_initsenses[] __initdata = { - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ + MPC85XX_INTERNAL_IRQ_SENSES, #if defined(CONFIG_PCI) (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 0: PCI1 slot */ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI1 slot */ @@ -182,7 +150,6 @@ void __init mpc85xx_cds_init_IRQ(void) { bd_t *binfo = (bd_t *) __res; - int i; /* Determine the Physical Address of the OpenPIC regs */ phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET; @@ -191,9 +158,13 @@ mpc85xx_cds_init_IRQ(void) OpenPIC_NumInitSenses = sizeof (mpc85xx_cds_openpic_initsenses); /* Skip reserved space and internal sources */ +#ifdef CONFIG_MPC8548 + openpic_set_sources(0, 48, OpenPIC_Addr + 0x10200); +#else openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200); +#endif /* Map PIC IRQs 0-11 */ - openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000); + openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000); /* we let openpic interrupts starting from an offset, to * leave space for cascading interrupts underneath. diff --git a/arch/ppc/platforms/85xx/sbc85xx.c b/arch/ppc/platforms/85xx/sbc85xx.c index 2d638c1..a7cb625 100644 --- a/arch/ppc/platforms/85xx/sbc85xx.c +++ b/arch/ppc/platforms/85xx/sbc85xx.c @@ -59,40 +59,8 @@ unsigned long pci_dram_offset = 0; extern unsigned long total_memory; /* in mm/init */ /* Internal interrupts are all Level Sensitive, and Positive Polarity */ - static u_char sbc8560_openpic_initsenses[] __initdata = { - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ + MPC85XX_INTERNAL_IRQ_SENSES, 0x0, /* External 0: */ 0x0, /* External 1: */ #if defined(CONFIG_PCI) @@ -159,7 +127,7 @@ sbc8560_init_IRQ(void) /* Skip reserved space and internal sources */ openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200); /* Map PIC IRQs 0-11 */ - openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000); + openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000); /* we let openpic interrupts starting from an offset, to * leave space for cascading interrupts underneath. diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c index bc95836..bc0a996 100644 --- a/arch/ppc/platforms/85xx/stx_gp3.c +++ b/arch/ppc/platforms/85xx/stx_gp3.c @@ -72,38 +72,7 @@ unsigned long pci_dram_offset = 0; /* Internal interrupts are all Level Sensitive, and Positive Polarity */ static u8 gp3_openpic_initsenses[] __initdata = { - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */ - (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ + MPC85XX_INTERNAL_IRQ_SENSES, 0x0, /* External 0: */ #if defined(CONFIG_PCI) (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI slot 0 */ @@ -200,7 +169,6 @@ static struct irqaction cpm2_irqaction = { static void __init gp3_init_IRQ(void) { - int i; bd_t *binfo = (bd_t *) __res; /* @@ -218,7 +186,7 @@ gp3_init_IRQ(void) openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200); /* Map PIC IRQs 0-11 */ - openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000); + openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000); /* * Let openpic interrupts starting from an offset, to diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h index 434fc51..a9b3332 100644 --- a/include/asm-ppc/irq.h +++ b/include/asm-ppc/irq.h @@ -176,7 +176,7 @@ static __inline__ int irq_canonicalize(int irq) */ #include -/* The MPC8560 openpic has 32 internal interrupts and 12 external +/* The MPC8548 openpic has 48 internal interrupts and 12 external * interrupts. * * We are "flattening" the interrupt vectors of the cascaded CPM @@ -184,7 +184,7 @@ static __inline__ int irq_canonicalize(int irq) * single integer. */ #define NR_CPM_INTS 64 -#define NR_EPIC_INTS 44 +#define NR_EPIC_INTS 60 #ifndef NR_8259_INTS #define NR_8259_INTS 0 #endif @@ -241,18 +241,18 @@ static __inline__ int irq_canonicalize(int irq) #define MPC85xx_IRQ_CPM (30 + MPC85xx_OPENPIC_IRQ_OFFSET) /* The 12 external interrupt lines */ -#define MPC85xx_IRQ_EXT0 (32 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT1 (33 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT2 (34 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT3 (35 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT4 (36 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT5 (37 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT6 (38 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT7 (39 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT8 (40 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT9 (41 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT10 (42 + MPC85xx_OPENPIC_IRQ_OFFSET) -#define MPC85xx_IRQ_EXT11 (43 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT0 (48 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT1 (49 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT2 (50 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT3 (51 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT4 (52 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT5 (53 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT6 (54 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT7 (55 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT8 (56 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT9 (57 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT10 (58 + MPC85xx_OPENPIC_IRQ_OFFSET) +#define MPC85xx_IRQ_EXT11 (59 + MPC85xx_OPENPIC_IRQ_OFFSET) /* CPM related interrupts */ #define SIU_INT_ERROR ((uint)0x00+CPM_IRQ_OFFSET) diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h index 95cc22d..516984e 100644 --- a/include/asm-ppc/mpc85xx.h +++ b/include/asm-ppc/mpc85xx.h @@ -134,6 +134,57 @@ enum ppc_sys_devices { MPC85xx_IIC2, }; +/* Internal interrupts are all Level Sensitive, and Positive Polarity */ +#define MPC85XX_INTERNAL_IRQ_SENSES \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 32 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 33 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 34 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 35 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 36 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 37 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 38 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 39 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 40 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 41 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 42 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 43 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 44 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 45 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 46 */ \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE) /* Internal 47 */ + #endif /* CONFIG_85xx */ #endif /* __ASM_MPC85xx_H__ */ #endif /* __KERNEL__ */ -- cgit v0.10.2 From 5be061eee931db2718feecaf10df17610386202b Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jun 2005 17:15:26 -0700 Subject: [PATCH] ppc32: Clean up NUM_TLBCAMS usage for Freescale Book-E PPC's Made the number of TLB CAM entries private and converted the board consumers to use num_tlbcam_entries which is setup at boot time from configuration registers. This way the only consumers of the #define NUM_TLBCAMS are the arrays used to manage the TLB. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/mm/fsl_booke_mmu.c b/arch/ppc/mm/fsl_booke_mmu.c index 36233bd..e07990e 100644 --- a/arch/ppc/mm/fsl_booke_mmu.c +++ b/arch/ppc/mm/fsl_booke_mmu.c @@ -64,6 +64,8 @@ extern unsigned long total_lowmem; extern unsigned long __max_low_memory; #define MAX_LOW_MEM CONFIG_LOWMEM_SIZE +#define NUM_TLBCAMS (16) + struct tlbcam { u32 MAS0; u32 MAS1; diff --git a/arch/ppc/mm/mmu_decl.h b/arch/ppc/mm/mmu_decl.h index ffcdb46..540f329 100644 --- a/arch/ppc/mm/mmu_decl.h +++ b/arch/ppc/mm/mmu_decl.h @@ -43,6 +43,8 @@ extern int mem_init_done; extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; +extern unsigned int num_tlbcam_entries; + /* ...and now those things that may be slightly different between processor * architectures. -- Dan */ diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index 5d2f3f6..81a3d74 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -66,7 +66,6 @@ void setbat(int index, unsigned long virt, unsigned long phys, #ifdef HAVE_TLBCAM extern unsigned int tlbcam_index; -extern unsigned int num_tlbcam_entries; extern unsigned long v_mapped_by_tlbcam(unsigned long va); extern unsigned long p_mapped_by_tlbcam(unsigned long pa); #else /* !HAVE_TLBCAM */ diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c index 583838a..d1c2c6c 100644 --- a/arch/ppc/platforms/85xx/mpc8540_ads.c +++ b/arch/ppc/platforms/85xx/mpc8540_ads.c @@ -88,7 +88,7 @@ mpc8540ads_setup_arch(void) #ifdef CONFIG_SERIAL_TEXT_DEBUG /* Invalidate the entry we stole earlier the serial ports * should be properly mapped */ - invalidate_tlbcam_entry(NUM_TLBCAMS - 1); + invalidate_tlbcam_entry(num_tlbcam_entries - 1); #endif /* setup the board related information for the enet controllers */ @@ -150,7 +150,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, struct uart_port p; /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */ - settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base, + settlbcam(num_tlbcam_entries - 1, binfo->bi_immr_base, binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0); memset(&p, 0, sizeof (p)); diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index bee6633..51964b3 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -446,7 +446,7 @@ mpc85xx_cds_setup_arch(void) #ifdef CONFIG_SERIAL_TEXT_DEBUG /* Invalidate the entry we stole earlier the serial ports * should be properly mapped */ - invalidate_tlbcam_entry(NUM_TLBCAMS - 1); + invalidate_tlbcam_entry(num_tlbcam_entries - 1); #endif /* setup the board related information for the enet controllers */ @@ -528,7 +528,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, struct uart_port p; /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */ - settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base, + settlbcam(num_tlbcam_entries - 1, binfo->bi_immr_base, binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0); memset(&p, 0, sizeof (p)); diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c index 7b9e154..42e960a 100644 --- a/arch/ppc/platforms/85xx/sbc8560.c +++ b/arch/ppc/platforms/85xx/sbc8560.c @@ -125,7 +125,7 @@ sbc8560_setup_arch(void) #ifdef CONFIG_SERIAL_TEXT_DEBUG /* Invalidate the entry we stole earlier the serial ports * should be properly mapped */ - invalidate_tlbcam_entry(NUM_TLBCAMS - 1); + invalidate_tlbcam_entry(num_tlbcam_entries - 1); #endif /* setup the board related information for the enet controllers */ @@ -176,7 +176,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #ifdef CONFIG_SERIAL_TEXT_DEBUG /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */ - settlbcam(NUM_TLBCAMS - 1, UARTA_ADDR, + settlbcam(num_tlbcam_entries - 1, UARTA_ADDR, UARTA_ADDR, 0x1000, _PAGE_IO, 0); #endif diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index a38606d..4d4b20c 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -267,8 +267,6 @@ extern unsigned long ioremap_bot, ioremap_base; #define _PMD_PRESENT_MASK (PAGE_MASK) #define _PMD_BAD (~PAGE_MASK) -#define NUM_TLBCAMS (16) - #elif defined(CONFIG_8xx) /* Definitions for 8xx embedded chips. */ #define _PAGE_PRESENT 0x0001 /* Page is valid */ -- cgit v0.10.2 From 1492ec8069ea6f82bc32df27cabbec72e554e2b8 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jun 2005 17:15:27 -0700 Subject: [PATCH] ppc32: Factor out common exception code into macro's for 4xx/Book-E 4xx and Book-E PPC's have several exception levels. The code to handle each level is fairly regular. Turning the code into macro's will ease the handling of future exception levels (debug) in forth coming chips. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 6615237..8377b6c 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -46,26 +46,23 @@ #ifdef CONFIG_BOOKE #include "head_booke.h" +#define TRANSFER_TO_HANDLER_EXC_LEVEL(exc_level) \ + mtspr exc_level##_SPRG,r8; \ + BOOKE_LOAD_EXC_LEVEL_STACK(exc_level); \ + lwz r0,GPR10-INT_FRAME_SIZE(r8); \ + stw r0,GPR10(r11); \ + lwz r0,GPR11-INT_FRAME_SIZE(r8); \ + stw r0,GPR11(r11); \ + mfspr r8,exc_level##_SPRG + .globl mcheck_transfer_to_handler mcheck_transfer_to_handler: - mtspr MCHECK_SPRG,r8 - BOOKE_LOAD_MCHECK_STACK - lwz r0,GPR10-INT_FRAME_SIZE(r8) - stw r0,GPR10(r11) - lwz r0,GPR11-INT_FRAME_SIZE(r8) - stw r0,GPR11(r11) - mfspr r8,MCHECK_SPRG + TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK) b transfer_to_handler_full .globl crit_transfer_to_handler crit_transfer_to_handler: - mtspr CRIT_SPRG,r8 - BOOKE_LOAD_CRIT_STACK - lwz r0,GPR10-INT_FRAME_SIZE(r8) - stw r0,GPR10(r11) - lwz r0,GPR11-INT_FRAME_SIZE(r8) - stw r0,GPR11(r11) - mfspr r8,CRIT_SPRG + TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT) /* fall through */ #endif @@ -783,99 +780,64 @@ exc_exit_restart_end: * time of the critical interrupt. * */ - .globl ret_from_crit_exc -ret_from_crit_exc: - REST_NVGPRS(r1) - lwz r3,_MSR(r1) - andi. r3,r3,MSR_PR - LOAD_MSR_KERNEL(r10,MSR_KERNEL) - bne user_exc_return - - lwz r0,GPR0(r1) - lwz r2,GPR2(r1) - REST_4GPRS(3, r1) - REST_2GPRS(7, r1) - - lwz r10,_XER(r1) - lwz r11,_CTR(r1) - mtspr SPRN_XER,r10 - mtctr r11 - - PPC405_ERR77(0,r1) - stwcx. r0,0,r1 /* to clear the reservation */ - - lwz r11,_LINK(r1) - mtlr r11 - lwz r10,_CCR(r1) - mtcrf 0xff,r10 #ifdef CONFIG_40x - /* avoid any possible TLB misses here by turning off MSR.DR, we - * assume the instructions here are mapped by a pinned TLB entry */ - li r10,MSR_IR - mtmsr r10 - isync - tophys(r1, r1) +#define PPC_40x_TURN_OFF_MSR_DR \ + /* avoid any possible TLB misses here by turning off MSR.DR, we \ + * assume the instructions here are mapped by a pinned TLB entry */ \ + li r10,MSR_IR; \ + mtmsr r10; \ + isync; \ + tophys(r1, r1); +#else +#define PPC_40x_TURN_OFF_MSR_DR #endif - lwz r9,_DEAR(r1) - lwz r10,_ESR(r1) - mtspr SPRN_DEAR,r9 - mtspr SPRN_ESR,r10 - lwz r11,_NIP(r1) - lwz r12,_MSR(r1) - mtspr SPRN_CSRR0,r11 - mtspr SPRN_CSRR1,r12 - lwz r9,GPR9(r1) - lwz r12,GPR12(r1) - lwz r10,GPR10(r1) - lwz r11,GPR11(r1) - lwz r1,GPR1(r1) - PPC405_ERR77_SYNC - rfci - b . /* prevent prefetch past rfci */ + +#define RET_FROM_EXC_LEVEL(exc_lvl_srr0, exc_lvl_srr1, exc_lvl_rfi) \ + REST_NVGPRS(r1); \ + lwz r3,_MSR(r1); \ + andi. r3,r3,MSR_PR; \ + LOAD_MSR_KERNEL(r10,MSR_KERNEL); \ + bne user_exc_return; \ + lwz r0,GPR0(r1); \ + lwz r2,GPR2(r1); \ + REST_4GPRS(3, r1); \ + REST_2GPRS(7, r1); \ + lwz r10,_XER(r1); \ + lwz r11,_CTR(r1); \ + mtspr SPRN_XER,r10; \ + mtctr r11; \ + PPC405_ERR77(0,r1); \ + stwcx. r0,0,r1; /* to clear the reservation */ \ + lwz r11,_LINK(r1); \ + mtlr r11; \ + lwz r10,_CCR(r1); \ + mtcrf 0xff,r10; \ + PPC_40x_TURN_OFF_MSR_DR; \ + lwz r9,_DEAR(r1); \ + lwz r10,_ESR(r1); \ + mtspr SPRN_DEAR,r9; \ + mtspr SPRN_ESR,r10; \ + lwz r11,_NIP(r1); \ + lwz r12,_MSR(r1); \ + mtspr exc_lvl_srr0,r11; \ + mtspr exc_lvl_srr1,r12; \ + lwz r9,GPR9(r1); \ + lwz r12,GPR12(r1); \ + lwz r10,GPR10(r1); \ + lwz r11,GPR11(r1); \ + lwz r1,GPR1(r1); \ + PPC405_ERR77_SYNC; \ + exc_lvl_rfi; \ + b .; /* prevent prefetch past exc_lvl_rfi */ + + .globl ret_from_crit_exc +ret_from_crit_exc: + RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) #ifdef CONFIG_BOOKE -/* - * Return from a machine check interrupt, similar to a critical - * interrupt. - */ .globl ret_from_mcheck_exc ret_from_mcheck_exc: - REST_NVGPRS(r1) - lwz r3,_MSR(r1) - andi. r3,r3,MSR_PR - LOAD_MSR_KERNEL(r10,MSR_KERNEL) - bne user_exc_return - - lwz r0,GPR0(r1) - lwz r2,GPR2(r1) - REST_4GPRS(3, r1) - REST_2GPRS(7, r1) - - lwz r10,_XER(r1) - lwz r11,_CTR(r1) - mtspr SPRN_XER,r10 - mtctr r11 - - stwcx. r0,0,r1 /* to clear the reservation */ - - lwz r11,_LINK(r1) - mtlr r11 - lwz r10,_CCR(r1) - mtcrf 0xff,r10 - lwz r9,_DEAR(r1) - lwz r10,_ESR(r1) - mtspr SPRN_DEAR,r9 - mtspr SPRN_ESR,r10 - lwz r11,_NIP(r1) - lwz r12,_MSR(r1) - mtspr SPRN_MCSRR0,r11 - mtspr SPRN_MCSRR1,r12 - lwz r9,GPR9(r1) - lwz r12,GPR12(r1) - lwz r10,GPR10(r1) - lwz r11,GPR11(r1) - lwz r1,GPR1(r1) - RFMCI + RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI) #endif /* CONFIG_BOOKE */ /* diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h index f213d12..9c50f9d 100644 --- a/arch/ppc/kernel/head_booke.h +++ b/arch/ppc/kernel/head_booke.h @@ -67,46 +67,36 @@ #define CRIT_STACK_TOP (exception_stack_top) #ifdef CONFIG_SMP -#define BOOKE_LOAD_CRIT_STACK \ +#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ mfspr r8,SPRN_PIR; \ mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \ neg r8,r8; \ - addis r8,r8,CRIT_STACK_TOP@ha; \ - addi r8,r8,CRIT_STACK_TOP@l -#define BOOKE_LOAD_MCHECK_STACK \ - mfspr r8,SPRN_PIR; \ - mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \ - neg r8,r8; \ - addis r8,r8,MCHECK_STACK_TOP@ha; \ - addi r8,r8,MCHECK_STACK_TOP@l + addis r8,r8,level##_STACK_TOP@ha; \ + addi r8,r8,level##_STACK_TOP@l #else -#define BOOKE_LOAD_CRIT_STACK \ - lis r8,CRIT_STACK_TOP@h; \ - ori r8,r8,CRIT_STACK_TOP@l -#define BOOKE_LOAD_MCHECK_STACK \ - lis r8,MCHECK_STACK_TOP@h; \ - ori r8,r8,MCHECK_STACK_TOP@l +#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ + lis r8,level##_STACK_TOP@h; \ + ori r8,r8,level##_STACK_TOP@l #endif /* - * Exception prolog for critical exceptions. This is a little different - * from the normal exception prolog above since a critical exception - * can potentially occur at any point during normal exception processing. - * Thus we cannot use the same SPRG registers as the normal prolog above. - * Instead we use a portion of the critical exception stack at low physical - * addresses. + * Exception prolog for critical/machine check exceptions. This is a + * little different from the normal exception prolog above since a + * critical/machine check exception can potentially occur at any point + * during normal exception processing. Thus we cannot use the same SPRG + * registers as the normal prolog above. Instead we use a portion of the + * critical/machine check exception stack at low physical addresses. */ - -#define CRITICAL_EXCEPTION_PROLOG \ - mtspr CRIT_SPRG,r8; \ - BOOKE_LOAD_CRIT_STACK; /* r8 points to the crit stack */ \ +#define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \ + mtspr exc_level##_SPRG,r8; \ + BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \ stw r10,GPR10-INT_FRAME_SIZE(r8); \ stw r11,GPR11-INT_FRAME_SIZE(r8); \ mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ + mfspr r11,exc_level_srr1; /* check whether user or kernel */\ andi. r11,r11,MSR_PR; \ mr r11,r8; \ - mfspr r8,CRIT_SPRG; \ + mfspr r8,exc_level##_SPRG; \ beq 1f; \ /* COMING FROM USER MODE */ \ mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ @@ -122,9 +112,9 @@ stw r12,_DEAR(r11); /* since they may have had stuff */\ mfspr r9,SPRN_ESR; /* in them at the point where the */\ stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,SPRN_CSRR0; \ + mfspr r12,exc_level_srr0; \ stw r1,GPR1(r11); \ - mfspr r9,SPRN_CSRR1; \ + mfspr r9,exc_level_srr1; \ stw r1,0(r11); \ mr r1,r11; \ rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ @@ -132,45 +122,10 @@ SAVE_4GPRS(3, r11); \ SAVE_2GPRS(7, r11) -/* - * Exception prolog for machine check exceptions. This is similar to - * the critical exception prolog, except that machine check exceptions - * have their stack. - */ -#define MCHECK_EXCEPTION_PROLOG \ - mtspr MCHECK_SPRG,r8; \ - BOOKE_LOAD_MCHECK_STACK; /* r8 points to the mcheck stack */\ - stw r10,GPR10-INT_FRAME_SIZE(r8); \ - stw r11,GPR11-INT_FRAME_SIZE(r8); \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - mr r11,r8; \ - mfspr r8,MCHECK_SPRG; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,SPRN_MCSRR0; \ - stw r1,GPR1(r11); \ - mfspr r9,SPRN_MCSRR1; \ - stw r1,0(r11); \ - mr r1,r11; \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) +#define CRITICAL_EXCEPTION_PROLOG \ + EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1) +#define MCHECK_EXCEPTION_PROLOG \ + EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1) /* * Exception vectors. @@ -237,7 +192,6 @@ label: EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ ret_from_except) - /* Check for a single step debug exception while in an exception * handler before state has been saved. This is to catch the case * where an instruction that we are trying to single step causes @@ -291,7 +245,7 @@ label: lwz r9,GPR9(r11); \ lwz r12,GPR12(r11); \ mtspr CRIT_SPRG,r8; \ - BOOKE_LOAD_CRIT_STACK; /* r8 points to the crit stack */ \ + BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \ lwz r10,GPR10-INT_FRAME_SIZE(r8); \ lwz r11,GPR11-INT_FRAME_SIZE(r8); \ mfspr r8,CRIT_SPRG; \ -- cgit v0.10.2 From ba8c6d534a0144375f910e764ec965d5e8059f7a Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jun 2005 17:15:28 -0700 Subject: [PATCH] ppc32: remove some unnecessary includes of prom.h Fight the Good Fight: Limit prom.h header creep. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c index e6348b5..86ca5cf 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.c +++ b/arch/ppc/platforms/83xx/mpc834x_sys.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c index d1c2c6c..a2ed611 100644 --- a/arch/ppc/platforms/85xx/mpc8540_ads.c +++ b/arch/ppc/platforms/85xx/mpc8540_ads.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c index 761b8c7..d87dfd5 100644 --- a/arch/ppc/platforms/85xx/mpc8560_ads.c +++ b/arch/ppc/platforms/85xx/mpc8560_ads.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c index 3039762..18e952d 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 51964b3..203b2ca 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c index 42e960a..3dbdd73 100644 --- a/arch/ppc/platforms/85xx/sbc8560.c +++ b/arch/ppc/platforms/85xx/sbc8560.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/platforms/85xx/sbc85xx.c b/arch/ppc/platforms/85xx/sbc85xx.c index a7cb625..4f6d1dd 100644 --- a/arch/ppc/platforms/85xx/sbc85xx.c +++ b/arch/ppc/platforms/85xx/sbc85xx.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c index bc0a996..9455bb6 100644 --- a/arch/ppc/platforms/85xx/stx_gp3.c +++ b/arch/ppc/platforms/85xx/stx_gp3.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index 000ba47c..b45d826 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c index ea26da0..7e272c5 100644 --- a/arch/ppc/syslib/open_pic2.c +++ b/arch/ppc/syslib/open_pic2.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/syslib/ppc83xx_setup.c b/arch/ppc/syslib/ppc83xx_setup.c index 843cf88..602a868 100644 --- a/arch/ppc/syslib/ppc83xx_setup.c +++ b/arch/ppc/syslib/ppc83xx_setup.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c index 455473f..ca95d79 100644 --- a/arch/ppc/syslib/ppc85xx_setup.c +++ b/arch/ppc/syslib/ppc85xx_setup.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -33,6 +32,8 @@ #include +extern void abort(void); + /* Return the amount of memory */ unsigned long __init mpc85xx_find_end_of_memory(void) -- cgit v0.10.2 From a70d439345875d476ede258094356e2acd09b1a1 Mon Sep 17 00:00:00 2001 From: Jakub Bogusz Date: Tue, 21 Jun 2005 17:15:29 -0700 Subject: [PATCH] ppc32: don't recursively crash in die() on CHRP/PReP machines This patch avoids recursive crash (leading to kernel stack overflow) in die() on CHRP/PReP machines when CONFIG_PMAC_BACKLIGHT=y. set_backlight_* functions are placed in pmac section, which is discarded when _machine != _MACH_Pmac. Signed-off-by: Jakub Bogusz Acked-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index c65731e..2ca8ecf 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -81,8 +81,10 @@ void die(const char * str, struct pt_regs * fp, long err) console_verbose(); spin_lock_irq(&die_lock); #ifdef CONFIG_PMAC_BACKLIGHT - set_backlight_enable(1); - set_backlight_level(BACKLIGHT_MAX); + if (_machine == _MACH_Pmac) { + set_backlight_enable(1); + set_backlight_level(BACKLIGHT_MAX); + } #endif printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); #ifdef CONFIG_PREEMPT -- cgit v0.10.2 From 6879dc137ea4efad65cab8bf8a7c0b742bcf92cc Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 21 Jun 2005 17:15:30 -0700 Subject: [PATCH] ppc32: Kill embedded system.map, use kallsyms This patch kills the whole embedded System.map mecanism and the bootloader-passed System.map that was used to provide symbol resolution in xmon. Instead, xmon now uses kallsyms like ppc64 does. No hurry getting that in Linus tree, let it be tested in -mm for a while first and make sure it doesn't break various embedded configs. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc/boot/ld.script b/arch/ppc/boot/ld.script index 6ee602d..9362193 100644 --- a/arch/ppc/boot/ld.script +++ b/arch/ppc/boot/ld.script @@ -58,9 +58,6 @@ SECTIONS *(.ramdisk) __ramdisk_end = .; . = ALIGN(4096); - __sysmap_begin = .; - *(.sysmap) - __sysmap_end = .; CONSTRUCTORS } _edata = .; diff --git a/arch/ppc/boot/openfirmware/Makefile b/arch/ppc/boot/openfirmware/Makefile index 4eacbd8..0341523 100644 --- a/arch/ppc/boot/openfirmware/Makefile +++ b/arch/ppc/boot/openfirmware/Makefile @@ -54,13 +54,10 @@ $(images)/ramdisk.image.gz: @echo ' RAM disk image must be provided separately' @/bin/false -objcpxmon-$(CONFIG_XMON) := --add-section=.sysmap=System.map \ - --set-section-flags=.sysmap=contents,alloc,load,readonly,data quiet_cmd_genimage = GEN $@ cmd_genimage = $(OBJCOPY) -R .comment \ --add-section=.image=$(images)/vmlinux.gz \ - --set-section-flags=.image=contents,alloc,load,readonly,data \ - $(objcpxmon-y) $< $@ + --set-section-flags=.image=contents,alloc,load,readonly,data $< $@ targets += image.o $(obj)/image.o: $(obj)/dummy.o $(images)/vmlinux.gz FORCE diff --git a/arch/ppc/boot/openfirmware/common.c b/arch/ppc/boot/openfirmware/common.c index 9e69527..0f46756 100644 --- a/arch/ppc/boot/openfirmware/common.c +++ b/arch/ppc/boot/openfirmware/common.c @@ -15,7 +15,6 @@ #include /* Information from the linker */ -extern char __sysmap_begin, __sysmap_end; extern int strcmp(const char *s1, const char *s2); extern char *avail_ram, *avail_high; @@ -116,14 +115,8 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) void make_bi_recs(unsigned long addr, char *name, unsigned int mach, unsigned long progend) { - unsigned long sysmap_size; struct bi_record *rec; - /* Figure out the size of a possible System.map we're going to - * pass along. - * */ - sysmap_size = (unsigned long)(&__sysmap_end) - - (unsigned long)(&__sysmap_begin); /* leave a 1MB gap then align to the next 1MB boundary */ addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); @@ -147,15 +140,6 @@ void make_bi_recs(unsigned long addr, char *name, unsigned int mach, rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); - if (sysmap_size) { - rec->tag = BI_SYSMAP; - rec->data[0] = (unsigned long)(&__sysmap_begin); - rec->data[1] = sysmap_size; - rec->size = sizeof(struct bi_record) + 2 * - sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - } - rec->tag = BI_LAST; rec->size = sizeof(struct bi_record); rec = (struct bi_record *)((unsigned long)rec + rec->size); diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile index c28061a..991b4cb 100644 --- a/arch/ppc/boot/simple/Makefile +++ b/arch/ppc/boot/simple/Makefile @@ -203,7 +203,7 @@ $(obj)/zvmlinux: $(OBJS) $(LIBS) $(srctree)/$(boot)/ld.script \ $(obj)/dummy.o $(obj)/image.o $(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/image.o $(LIBS) $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab \ - -R .stabstr -R .ramdisk -R .sysmap + -R .stabstr -R .ramdisk $(obj)/zvmlinux.initrd: $(OBJS) $(LIBS) $(srctree)/$(boot)/ld.script \ $(images)/vmlinux.gz $(obj)/dummy.o @@ -215,7 +215,7 @@ $(obj)/zvmlinux.initrd: $(OBJS) $(LIBS) $(srctree)/$(boot)/ld.script \ $(obj)/dummy.o $(obj)/image.o $(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/image.o $(LIBS) $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab \ - -R .stabstr -R .sysmap + -R .stabstr # Sort-of dummy rules, that let us format the image we want. zImage: $(images)/$(zimage-y) $(obj)/zvmlinux diff --git a/arch/ppc/boot/utils/addSystemMap.c b/arch/ppc/boot/utils/addSystemMap.c deleted file mode 100644 index 4654f89..0000000 --- a/arch/ppc/boot/utils/addSystemMap.c +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include -#include -#include - -void xlate( char * inb, char * trb, unsigned len ) -{ - unsigned i; - for ( i=0; i> 4; - char c2 = c & 0xf; - if ( c1 > 9 ) - c1 = c1 + 'A' - 10; - else - c1 = c1 + '0'; - if ( c2 > 9 ) - c2 = c2 + 'A' - 10; - else - c2 = c2 + '0'; - *trb++ = c1; - *trb++ = c2; - } - *trb = 0; -} - -#define ElfHeaderSize (64 * 1024) -#define ElfPages (ElfHeaderSize / 4096) -#define KERNELBASE (0xc0000000) - -void get4k( /*istream *inf*/FILE *file, char *buf ) -{ - unsigned j; - unsigned num = fread(buf, 1, 4096, file); - for ( j=num; j<4096; ++j ) - buf[j] = 0; -} - -void put4k( /*ostream *outf*/FILE *file, char *buf ) -{ - fwrite(buf, 1, 4096, file); -} - -int main(int argc, char **argv) -{ - char inbuf[4096]; - FILE *ramDisk = NULL; - FILE *inputVmlinux = NULL; - FILE *outputVmlinux = NULL; - unsigned i = 0; - unsigned long ramFileLen = 0; - unsigned long ramLen = 0; - unsigned long roundR = 0; - unsigned long kernelLen = 0; - unsigned long actualKernelLen = 0; - unsigned long round = 0; - unsigned long roundedKernelLen = 0; - unsigned long ramStartOffs = 0; - unsigned long ramPages = 0; - unsigned long roundedKernelPages = 0; - if ( argc < 2 ) { - printf("Name of System Map file missing.\n"); - exit(1); - } - - if ( argc < 3 ) { - printf("Name of vmlinux file missing.\n"); - exit(1); - } - - if ( argc < 4 ) { - printf("Name of vmlinux output file missing.\n"); - exit(1); - } - - ramDisk = fopen(argv[1], "r"); - if ( ! ramDisk ) { - printf("System Map file \"%s\" failed to open.\n", argv[1]); - exit(1); - } - inputVmlinux = fopen(argv[2], "r"); - if ( ! inputVmlinux ) { - printf("vmlinux file \"%s\" failed to open.\n", argv[2]); - exit(1); - } - outputVmlinux = fopen(argv[3], "w"); - if ( ! outputVmlinux ) { - printf("output vmlinux file \"%s\" failed to open.\n", argv[3]); - exit(1); - } - fseek(ramDisk, 0, SEEK_END); - ramFileLen = ftell(ramDisk); - fseek(ramDisk, 0, SEEK_SET); - printf("%s file size = %ld\n", argv[1], ramFileLen); - - ramLen = ramFileLen; - - roundR = 4096 - (ramLen % 4096); - if ( roundR ) { - printf("Rounding System Map file up to a multiple of 4096, adding %ld\n", roundR); - ramLen += roundR; - } - - printf("Rounded System Map size is %ld\n", ramLen); - fseek(inputVmlinux, 0, SEEK_END); - kernelLen = ftell(inputVmlinux); - fseek(inputVmlinux, 0, SEEK_SET); - printf("kernel file size = %ld\n", kernelLen); - if ( kernelLen == 0 ) { - printf("You must have a linux kernel specified as argv[2]\n"); - exit(1); - } - - actualKernelLen = kernelLen - ElfHeaderSize; - - printf("actual kernel length (minus ELF header) = %ld\n", actualKernelLen); - - round = actualKernelLen % 4096; - roundedKernelLen = actualKernelLen; - if ( round ) - roundedKernelLen += (4096 - round); - - printf("actual kernel length rounded up to a 4k multiple = %ld\n", roundedKernelLen); - - ramStartOffs = roundedKernelLen; - ramPages = ramLen / 4096; - - printf("System map pages to copy = %ld\n", ramPages); - - // Copy 64K ELF header - for (i=0; i<(ElfPages); ++i) { - get4k( inputVmlinux, inbuf ); - put4k( outputVmlinux, inbuf ); - } - - - - roundedKernelPages = roundedKernelLen / 4096; - - fseek(inputVmlinux, ElfHeaderSize, SEEK_SET); - - { - for ( i=0; i= (KERNELBASE)) ? data[0] : - (data[0]+KERNELBASE)); - sysmap_size = data[1]; - break; #ifdef CONFIG_BLK_DEV_INITRD case BI_INITRD: initrd_start = data[0] + KERNELBASE; diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index c8529d0..334ef41 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -96,9 +96,6 @@ extern struct task_struct *current_set[NR_CPUS]; char *klimit = _end; struct mem_pieces phys_avail; -extern char *sysmap; -extern unsigned long sysmap_size; - /* * this tells the system to map all of ram with the segregs * (i.e. page tables) instead of the bats. @@ -442,12 +439,6 @@ void __init mem_init(void) if (agp_special_page) SetPageReserved(virt_to_page(agp_special_page)); #endif - if ( sysmap ) - for (addr = (unsigned long)sysmap; - addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ; - addr += PAGE_SIZE) - SetPageReserved(virt_to_page(addr)); - for (addr = PAGE_OFFSET; addr < (unsigned long)high_memory; addr += PAGE_SIZE) { if (!PageReserved(virt_to_page(addr))) @@ -482,9 +473,7 @@ void __init mem_init(void) codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), initpages<< (PAGE_SHIFT-10), (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); - if (sysmap) - printk("System.map loaded at 0x%08x for debugger, size: %ld bytes\n", - (unsigned int)sysmap, sysmap_size); + #ifdef CONFIG_PPC_PMAC if (agp_special_page) printk(KERN_INFO "AGP special page: 0x%08lx\n", agp_special_page); @@ -534,9 +523,6 @@ set_phys_avail(unsigned long total_memory) if (rtas_data) mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1); #endif - /* remove the sysmap pages from the available memory */ - if (sysmap) - mem_pieces_remove(&phys_avail, __pa(sysmap), sysmap_size, 1); #ifdef CONFIG_PPC_PMAC /* Because of some uninorth weirdness, we need a page of * memory as high as possible (it must be outside of the diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index 8565f49..be7869e 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -93,8 +94,7 @@ static void take_input(char *); static unsigned read_spr(int); static void write_spr(int, unsigned); static void super_regs(void); -static void print_sysmap(void); -static void sysmap_lookup(void); +static void symbol_lookup(void); static void remove_bpts(void); static void insert_bpts(void); static struct bpt *at_breakpoint(unsigned pc); @@ -103,7 +103,6 @@ static void cacheflush(void); #ifdef CONFIG_SMP static void cpu_cmd(void); #endif /* CONFIG_SMP */ -static int pretty_print_addr(unsigned long addr); static void csum(void); #ifdef CONFIG_BOOTX_TEXT static void vidcmds(void); @@ -120,8 +119,6 @@ extern void longjmp(u_int *, int); extern void xmon_enter(void); extern void xmon_leave(void); -extern char* xmon_find_symbol(unsigned long addr, unsigned long* saddr); -extern unsigned long xmon_symbol_to_addr(char* symbol); static unsigned start_tb[NR_CPUS][2]; static unsigned stop_tb[NR_CPUS][2]; @@ -148,7 +145,6 @@ Commands:\n\ mm move a block of memory\n\ ms set a block of memory\n\ md compare two blocks of memory\n\ - M print System.map\n\ r print registers\n\ S print special registers\n\ t print backtrace\n\ @@ -175,6 +171,35 @@ extern inline void __delay(unsigned int loops) "r" (loops) : "ctr"); } +/* Print an address in numeric and symbolic form (if possible) */ +static void xmon_print_symbol(unsigned long address, const char *mid, + const char *after) +{ + char *modname; + const char *name = NULL; + unsigned long offset, size; + static char tmpstr[128]; + + printf("%.8lx", address); + if (setjmp(bus_error_jmp) == 0) { + debugger_fault_handler = handle_fault; + sync(); + name = kallsyms_lookup(address, &size, &offset, &modname, + tmpstr); + sync(); + /* wait a little while to see if we get a machine check */ + __delay(200); + } + debugger_fault_handler = NULL; + + if (name) { + printf("%s%s+%#lx/%#lx", mid, name, offset, size); + if (modname) + printf(" [%s]", modname); + } + printf("%s", after); +} + static void get_tb(unsigned *p) { unsigned hi, lo, hiagain; @@ -454,7 +479,7 @@ cmds(struct pt_regs *excp) dump(); break; case 'l': - sysmap_lookup(); + symbol_lookup(); break; case 'r': if (excp != NULL) @@ -466,9 +491,6 @@ cmds(struct pt_regs *excp) else excprint(excp); break; - case 'M': - print_sysmap(); - break; case 'S': super_regs(); break; @@ -825,20 +847,19 @@ backtrace(struct pt_regs *excp) for (; sp != 0; sp = stack[0]) { if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) break; - pretty_print_addr(stack[1]); - printf(" "); + printf("[%.8lx] ", stack); + xmon_print_symbol(stack[1], " ", "\n"); if (stack[1] == (unsigned) &ret_from_except || stack[1] == (unsigned) &ret_from_except_full || stack[1] == (unsigned) &ret_from_syscall) { if (mread(sp+16, ®s, sizeof(regs)) != sizeof(regs)) break; - printf("\nexception:%x [%x] %x ", regs.trap, sp+16, + printf("exception:%x [%x] %x\n", regs.trap, sp+16, regs.nip); sp = regs.gpr[1]; if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) break; } - printf("\n"); } } @@ -859,11 +880,10 @@ excprint(struct pt_regs *fp) #ifdef CONFIG_SMP printf("cpu %d: ", smp_processor_id()); #endif /* CONFIG_SMP */ - printf("vector: %x at pc = ", fp->trap); - pretty_print_addr(fp->nip); - printf(", lr = "); - pretty_print_addr(fp->link); - printf("\nmsr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp); + printf("vector: %x at pc=", fp->trap); + xmon_print_symbol(fp->nip, ": ", ", lr="); + xmon_print_symbol(fp->link, ": ", "\n"); + printf("msr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp); trap = TRAP(fp); if (trap == 0x300 || trap == 0x600) printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr); @@ -951,24 +971,6 @@ extern char exc_prolog; extern char dec_exc; void -print_sysmap(void) -{ - extern char *sysmap; - if ( sysmap ) { - printf("System.map: \n"); - if( setjmp(bus_error_jmp) == 0 ) { - debugger_fault_handler = handle_fault; - sync(); - xmon_puts(sysmap); - sync(); - } - debugger_fault_handler = NULL; - } - else - printf("No System.map\n"); -} - -void super_regs(void) { int i, cmd; @@ -1738,7 +1740,7 @@ scanhex(unsigned *vp) printf("invalid register name '%%%s'\n", regname); return 0; } else if (c == '$') { - static char symname[64]; + static char symname[128]; int i; for (i=0; i<63; i++) { c = inchar(); @@ -1749,7 +1751,14 @@ scanhex(unsigned *vp) symname[i] = c; } symname[i++] = 0; - *vp = xmon_symbol_to_addr(symname); + *vp = 0; + if (setjmp(bus_error_jmp) == 0) { + debugger_fault_handler = handle_fault; + sync(); + *vp = kallsyms_lookup_name(symname); + sync(); + } + debugger_fault_handler = NULL; if (!(*vp)) { printf("unknown symbol\n"); return 0; @@ -1840,169 +1849,34 @@ take_input(char *str) lineptr = str; } -void -sysmap_lookup(void) +static void +symbol_lookup(void) { int type = inchar(); unsigned addr; - static char tmp[64]; - char* cur; - - extern char *sysmap; - extern unsigned long sysmap_size; - if ( !sysmap || !sysmap_size ) - return; - - switch(type) { - case 'a': - if (scanhex(&addr)) { - pretty_print_addr(addr); - printf("\n"); - } - termch = 0; - break; - case 's': - getstring(tmp, 64); - if( setjmp(bus_error_jmp) == 0 ) { - debugger_fault_handler = handle_fault; - sync(); - cur = sysmap; - do { - cur = strstr(cur, tmp); - if (cur) { - static char res[64]; - char *p, *d; - p = cur; - while(p > sysmap && *p != 10) - p--; - if (*p == 10) p++; - d = res; - while(*p && p < (sysmap + sysmap_size) && *p != 10) - *(d++) = *(p++); - *(d++) = 0; - printf("%s\n", res); - cur++; - } - } while (cur); - sync(); - } - debugger_fault_handler = NULL; - termch = 0; - break; - } -} + static char tmp[128]; -static int -pretty_print_addr(unsigned long addr) -{ - char *sym; - unsigned long saddr; - - printf("%08x", addr); - sym = xmon_find_symbol(addr, &saddr); - if (sym) - printf(" (%s+0x%x)", sym, addr-saddr); - return (sym != 0); -} - -char* -xmon_find_symbol(unsigned long addr, unsigned long* saddr) -{ - static char rbuffer[64]; - char *p, *ep, *limit; - unsigned long prev, next; - char* psym; - - extern char *sysmap; - extern unsigned long sysmap_size; - if ( !sysmap || !sysmap_size ) - return NULL; - - prev = 0; - psym = NULL; - p = sysmap; - limit = p + sysmap_size; - if( setjmp(bus_error_jmp) == 0 ) { - debugger_fault_handler = handle_fault; - sync(); - do { - next = simple_strtoul(p, &p, 16); - if (next > addr && prev <= addr) { - if (!psym) - goto bail; - ep = rbuffer; - p = psym; - while(*p && p < limit && *p == 32) - p++; - while(*p && p < limit && *p != 10 && (ep - rbuffer) < 63) - *(ep++) = *(p++); - *(ep++) = 0; - if (saddr) - *saddr = prev; - debugger_fault_handler = NULL; - return rbuffer; - } - prev = next; - psym = p; - while(*p && p < limit && *p != 10) - p++; - if (*p) p++; - } while(*p && p < limit && next); -bail: - sync(); + switch (type) { + case 'a': + if (scanhex(&addr)) + xmon_print_symbol(addr, ": ", "\n"); + termch = 0; + break; + case 's': + getstring(tmp, 64); + if (setjmp(bus_error_jmp) == 0) { + debugger_fault_handler = handle_fault; + sync(); + addr = kallsyms_lookup_name(tmp); + if (addr) + printf("%s: %lx\n", tmp, addr); + else + printf("Symbol '%s' not found.\n", tmp); + sync(); + } + debugger_fault_handler = NULL; + termch = 0; + break; } - debugger_fault_handler = NULL; - return NULL; } -unsigned long -xmon_symbol_to_addr(char* symbol) -{ - char *p, *cur; - char *match = NULL; - int goodness = 0; - int result = 0; - - extern char *sysmap; - extern unsigned long sysmap_size; - if ( !sysmap || !sysmap_size ) - return 0; - - if( setjmp(bus_error_jmp) == 0 ) { - debugger_fault_handler = handle_fault; - sync(); - cur = sysmap; - while(cur) { - cur = strstr(cur, symbol); - if (cur) { - int gd = 1; - - /* best match if equal, better match if - * begins with - */ - if (cur == sysmap || *(cur-1) == ' ') { - gd++; - if (cur[strlen(symbol)] == 10) - gd++; - } - if (gd > goodness) { - match = cur; - goodness = gd; - if (gd == 3) - break; - } - cur++; - } - } - if (goodness) { - p = match; - while(p > sysmap && *p != 10) - p--; - if (*p == 10) p++; - result = simple_strtoul(p, &p, 16); - } - sync(); - } - debugger_fault_handler = NULL; - return result; -} diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c index 3c0ccb2..7f6e13a 100644 --- a/arch/ppc64/xmon/xmon.c +++ b/arch/ppc64/xmon/xmon.c @@ -2247,7 +2247,14 @@ scanhex(unsigned long *vp) tmpstr[i] = c; } tmpstr[i++] = 0; - *vp = kallsyms_lookup_name(tmpstr); + *vp = 0; + if (setjmp(bus_error_jmp) == 0) { + catch_memory_errors = 1; + sync(); + *vp = kallsyms_lookup_name(tmpstr); + sync(); + } + catch_memory_errors = 0; if (!(*vp)) { printf("unknown symbol '%s'\n", tmpstr); return 0; -- cgit v0.10.2 From 20cee16ced631f70a62c97bdebae08a1c9470448 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 21 Jun 2005 17:15:31 -0700 Subject: [PATCH] ppc64: Abolish ioremap_mm Currently ppc64 has two mm_structs for the kernel, init_mm and also ioremap_mm. The latter really isn't necessary: this patch abolishes it, instead restricting vmallocs to the lower 1TB of the init_mm's range and placing io mappings in the upper 1TB. This simplifies the code in a number of places and eliminates an unecessary set of pagetables. It also tweaks the unmap/free path a little, allowing us to remove the unmap_im_area() set of page table walkers, replacing them with unmap_vm_area(). Signed-off-by: David Gibson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c index d63d41f..af5272f 100644 --- a/arch/ppc64/kernel/eeh.c +++ b/arch/ppc64/kernel/eeh.c @@ -505,7 +505,7 @@ static inline unsigned long eeh_token_to_phys(unsigned long token) pte_t *ptep; unsigned long pa; - ptep = find_linux_pte(ioremap_mm.pgd, token); + ptep = find_linux_pte(init_mm.pgd, token); if (!ptep) return token; pa = pte_pfn(*ptep) << PAGE_SHIFT; diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 346dbf6..02c8f4e 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -2121,10 +2121,6 @@ empty_zero_page: swapper_pg_dir: .space 4096 - .globl ioremap_dir -ioremap_dir: - .space 4096 - #ifdef CONFIG_SMP /* 1 page segment table per cpu (max 48, cpu0 allocated at STAB0_PHYS_ADDR) */ .globl stab_array diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index cdfecbe..aba8955 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -58,14 +58,6 @@ struct task_struct *last_task_used_math = NULL; struct task_struct *last_task_used_altivec = NULL; #endif -struct mm_struct ioremap_mm = { - .pgd = ioremap_dir, - .mm_users = ATOMIC_INIT(2), - .mm_count = ATOMIC_INIT(1), - .cpu_vm_mask = CPU_MASK_ALL, - .page_table_lock = SPIN_LOCK_UNLOCKED, -}; - /* * Make sure the floating-point register state in the * the thread_struct is up to date for task tsk. diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c index 0a0f970..87d0525 100644 --- a/arch/ppc64/mm/hash_utils.c +++ b/arch/ppc64/mm/hash_utils.c @@ -310,10 +310,6 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) vsid = get_vsid(mm->context.id, ea); break; - case IO_REGION_ID: - mm = &ioremap_mm; - vsid = get_kernel_vsid(ea); - break; case VMALLOC_REGION_ID: mm = &init_mm; vsid = get_kernel_vsid(ea); diff --git a/arch/ppc64/mm/imalloc.c b/arch/ppc64/mm/imalloc.c index cb8727f..b6e75b8 100644 --- a/arch/ppc64/mm/imalloc.c +++ b/arch/ppc64/mm/imalloc.c @@ -15,6 +15,7 @@ #include #include #include +#include static DECLARE_MUTEX(imlist_sem); struct vm_struct * imlist = NULL; @@ -285,29 +286,32 @@ struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size, return area; } -unsigned long im_free(void * addr) +void im_free(void * addr) { struct vm_struct **p, *tmp; - unsigned long ret_size = 0; if (!addr) - return ret_size; - if ((PAGE_SIZE-1) & (unsigned long) addr) { + return; + if ((unsigned long) addr & ~PAGE_MASK) { printk(KERN_ERR "Trying to %s bad address (%p)\n", __FUNCTION__, addr); - return ret_size; + return; } down(&imlist_sem); for (p = &imlist ; (tmp = *p) ; p = &tmp->next) { if (tmp->addr == addr) { - ret_size = tmp->size; *p = tmp->next; + + /* XXX: do we need the lock? */ + spin_lock(&init_mm.page_table_lock); + unmap_vm_area(tmp); + spin_unlock(&init_mm.page_table_lock); + kfree(tmp); up(&imlist_sem); - return ret_size; + return; } } up(&imlist_sem); printk(KERN_ERR "Trying to %s nonexistent area (%p)\n", __FUNCTION__, addr); - return ret_size; } diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index 4b42aff..6fa1e64 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c @@ -73,9 +73,6 @@ static unsigned long phbs_io_bot = PHBS_IO_BASE; extern pgd_t swapper_pg_dir[]; extern struct task_struct *current_set[NR_CPUS]; -extern pgd_t ioremap_dir[]; -pgd_t * ioremap_pgd = (pgd_t *)&ioremap_dir; - unsigned long klimit = (unsigned long)_end; unsigned long _SDR1=0; @@ -137,69 +134,6 @@ void iounmap(volatile void __iomem *addr) #else -static void unmap_im_area_pte(pmd_t *pmd, unsigned long addr, - unsigned long end) -{ - pte_t *pte; - - pte = pte_offset_kernel(pmd, addr); - do { - pte_t ptent = ptep_get_and_clear(&ioremap_mm, addr, pte); - WARN_ON(!pte_none(ptent) && !pte_present(ptent)); - } while (pte++, addr += PAGE_SIZE, addr != end); -} - -static inline void unmap_im_area_pmd(pud_t *pud, unsigned long addr, - unsigned long end) -{ - pmd_t *pmd; - unsigned long next; - - pmd = pmd_offset(pud, addr); - do { - next = pmd_addr_end(addr, end); - if (pmd_none_or_clear_bad(pmd)) - continue; - unmap_im_area_pte(pmd, addr, next); - } while (pmd++, addr = next, addr != end); -} - -static inline void unmap_im_area_pud(pgd_t *pgd, unsigned long addr, - unsigned long end) -{ - pud_t *pud; - unsigned long next; - - pud = pud_offset(pgd, addr); - do { - next = pud_addr_end(addr, end); - if (pud_none_or_clear_bad(pud)) - continue; - unmap_im_area_pmd(pud, addr, next); - } while (pud++, addr = next, addr != end); -} - -static void unmap_im_area(unsigned long addr, unsigned long end) -{ - struct mm_struct *mm = &ioremap_mm; - unsigned long next; - pgd_t *pgd; - - spin_lock(&mm->page_table_lock); - - pgd = pgd_offset_i(addr); - flush_cache_vunmap(addr, end); - do { - next = pgd_addr_end(addr, end); - if (pgd_none_or_clear_bad(pgd)) - continue; - unmap_im_area_pud(pgd, addr, next); - } while (pgd++, addr = next, addr != end); - flush_tlb_kernel_range(start, end); - - spin_unlock(&mm->page_table_lock); -} - /* * map_io_page currently only called by __ioremap * map_io_page adds an entry to the ioremap page table @@ -214,21 +148,21 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags) unsigned long vsid; if (mem_init_done) { - spin_lock(&ioremap_mm.page_table_lock); - pgdp = pgd_offset_i(ea); - pudp = pud_alloc(&ioremap_mm, pgdp, ea); + spin_lock(&init_mm.page_table_lock); + pgdp = pgd_offset_k(ea); + pudp = pud_alloc(&init_mm, pgdp, ea); if (!pudp) return -ENOMEM; - pmdp = pmd_alloc(&ioremap_mm, pudp, ea); + pmdp = pmd_alloc(&init_mm, pudp, ea); if (!pmdp) return -ENOMEM; - ptep = pte_alloc_kernel(&ioremap_mm, pmdp, ea); + ptep = pte_alloc_kernel(&init_mm, pmdp, ea); if (!ptep) return -ENOMEM; pa = abs_to_phys(pa); - set_pte_at(&ioremap_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, + set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); - spin_unlock(&ioremap_mm.page_table_lock); + spin_unlock(&init_mm.page_table_lock); } else { unsigned long va, vpn, hash, hpteg; @@ -267,13 +201,9 @@ static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa, for (i = 0; i < size; i += PAGE_SIZE) if (map_io_page(ea+i, pa+i, flags)) - goto failure; + return NULL; return (void __iomem *) (ea + (addr & ~PAGE_MASK)); - failure: - if (mem_init_done) - unmap_im_area(ea, ea + size); - return NULL; } @@ -381,19 +311,14 @@ int __ioremap_explicit(unsigned long pa, unsigned long ea, */ void iounmap(volatile void __iomem *token) { - unsigned long address, size; void *addr; if (!mem_init_done) return; addr = (void *) ((unsigned long __force) token & PAGE_MASK); - - if ((size = im_free(addr)) == 0) - return; - address = (unsigned long)addr; - unmap_im_area(address, address + size); + im_free(addr); } static int iounmap_subset_regions(unsigned long addr, unsigned long size) diff --git a/include/asm-ppc64/imalloc.h b/include/asm-ppc64/imalloc.h index 3a45e91..e46ff68 100644 --- a/include/asm-ppc64/imalloc.h +++ b/include/asm-ppc64/imalloc.h @@ -4,9 +4,9 @@ /* * Define the address range of the imalloc VM area. */ -#define PHBS_IO_BASE IOREGIONBASE -#define IMALLOC_BASE (IOREGIONBASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */ -#define IMALLOC_END (IOREGIONBASE + EADDR_MASK) +#define PHBS_IO_BASE VMALLOC_END +#define IMALLOC_BASE (PHBS_IO_BASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */ +#define IMALLOC_END (VMALLOC_START + EADDR_MASK) /* imalloc region types */ @@ -18,7 +18,9 @@ extern struct vm_struct * im_get_free_area(unsigned long size); extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size, - int region_type); -unsigned long im_free(void *addr); + int region_type); +extern void im_free(void *addr); + +extern unsigned long ioremap_bot; #endif /* _PPC64_IMALLOC_H */ diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h index bcd2178..257d87e 100644 --- a/include/asm-ppc64/page.h +++ b/include/asm-ppc64/page.h @@ -202,9 +202,7 @@ extern u64 ppc64_pft_size; /* Log 2 of page table size */ #define PAGE_OFFSET ASM_CONST(0xC000000000000000) #define KERNELBASE PAGE_OFFSET #define VMALLOCBASE ASM_CONST(0xD000000000000000) -#define IOREGIONBASE ASM_CONST(0xE000000000000000) -#define IO_REGION_ID (IOREGIONBASE >> REGION_SHIFT) #define VMALLOC_REGION_ID (VMALLOCBASE >> REGION_SHIFT) #define KERNEL_REGION_ID (KERNELBASE >> REGION_SHIFT) #define USER_REGION_ID (0UL) diff --git a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h index 264c4f7..46cf61c 100644 --- a/include/asm-ppc64/pgtable.h +++ b/include/asm-ppc64/pgtable.h @@ -53,7 +53,8 @@ * Define the address range of the vmalloc VM area. */ #define VMALLOC_START (0xD000000000000000ul) -#define VMALLOC_END (VMALLOC_START + EADDR_MASK) +#define VMALLOC_SIZE (0x10000000000UL) +#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE) /* * Bits in a linux-style PTE. These match the bits in the @@ -239,9 +240,6 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot) /* This now only contains the vmalloc pages */ #define pgd_offset_k(address) pgd_offset(&init_mm, address) -/* to find an entry in the ioremap page-table-directory */ -#define pgd_offset_i(address) (ioremap_pgd + pgd_index(address)) - /* * The following only work if pte_present() is true. * Undefined behaviour if not.. @@ -459,15 +457,12 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr, #define __HAVE_ARCH_PTE_SAME #define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0) -extern unsigned long ioremap_bot, ioremap_base; - #define pmd_ERROR(e) \ printk("%s:%d: bad pmd %08x.\n", __FILE__, __LINE__, pmd_val(e)) #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %08x.\n", __FILE__, __LINE__, pgd_val(e)) extern pgd_t swapper_pg_dir[]; -extern pgd_t ioremap_dir[]; extern void paging_init(void); diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h index 809c634b..3084099 100644 --- a/include/asm-ppc64/processor.h +++ b/include/asm-ppc64/processor.h @@ -430,16 +430,6 @@ struct thread_struct { } /* - * Note: the vm_start and vm_end fields here should *not* - * be in kernel space. (Could vm_end == vm_start perhaps?) - */ -#define IOREMAP_MMAP { &ioremap_mm, 0, 0x1000, NULL, \ - PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, \ - 1, NULL, NULL } - -extern struct mm_struct ioremap_mm; - -/* * Return saved PC of a blocked thread. For now, this is the "user" PC */ #define thread_saved_pc(tsk) \ -- cgit v0.10.2 From 723e2b35e43dcbcfd737c40453caa7d198092d23 Mon Sep 17 00:00:00 2001 From: Sven Luther Date: Tue, 21 Jun 2005 17:15:32 -0700 Subject: [PATCH] ppc64: override command line AS/LD/CC variables when adding -m64 and co for biarch compilers The following kind of calls currently fails : make ARCH=ppc64 CC="gcc-3.4" Since the code for detecting a biarch compiler and adding the needed 64bit magic argument fails if the AS/LD/CC commands are overriden in the command line. The attached patch fixes this by using the make override and += directive, but i am not 100% sure this will work without gmake, as i am no Makefile expert. Cc: Paul Mackerras Cc: Anton Blanchard Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 691f300..33c752c 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -35,9 +35,9 @@ CROSS32AS := $(AS) -a32 CROSS32LD := $(LD) -m elf32ppc CROSS32OBJCOPY := $(OBJCOPY) endif -AS := $(AS) -a64 -LD := $(LD) -m elf64ppc -CC := $(CC) -m64 +override AS += -a64 +override LD += -m elf64ppc +override CC += -m64 endif export CROSS32CC CROSS32AS CROSS32LD CROSS32OBJCOPY -- cgit v0.10.2 From 0e3e4a1c4dade7872fdb04a5e735ae26d8e2fbfb Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:33 -0700 Subject: [PATCH] ppc64 iSeries: remove iSeries_proc.h include/asm-ppc64/iSeries/iSeries_proc.h just contains a declaration of a function that no longer exists. Remove it. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/iSeries_proc.c b/arch/ppc64/kernel/iSeries_proc.c index 0cc58dd..bf85a1f 100644 --- a/arch/ppc64/kernel/iSeries_proc.c +++ b/arch/ppc64/kernel/iSeries_proc.c @@ -29,7 +29,6 @@ #include #include #include -#include static int __init iseries_proc_create(void) { diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 6d06eb5..e80cfc5 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -55,7 +55,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/viopath.c b/arch/ppc64/kernel/viopath.c index 2ed8ee0..8caa078 100644 --- a/arch/ppc64/kernel/viopath.c +++ b/arch/ppc64/kernel/viopath.c @@ -48,7 +48,6 @@ #include #include #include -#include #include /* Status of the path to each other partition in the system. diff --git a/include/asm-ppc64/iSeries/iSeries_proc.h b/include/asm-ppc64/iSeries/iSeries_proc.h deleted file mode 100644 index adb6dc1..0000000 --- a/include/asm-ppc64/iSeries/iSeries_proc.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * iSeries_proc.h - * Copyright (C) 2001 Kyle A. Lucke IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ISERIES_PROC_H -#define _ISERIES_PROC_H - -extern void iSeries_proc_early_init(void); - -#endif /* _iSeries_PROC_H */ -- cgit v0.10.2 From 45dc76aaf63fc336527da80337d3e3684f50f387 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:33 -0700 Subject: [PATCH] ppc64 iSeries: header file white space cleanups This patch just contains white space and comment cleanups in the iSeries headers files. There are no semantic changes. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-ppc64/iSeries/HvCall.h b/include/asm-ppc64/iSeries/HvCall.h index d9a2e74..c903387 100644 --- a/include/asm-ppc64/iSeries/HvCall.h +++ b/include/asm-ppc64/iSeries/HvCall.h @@ -1,34 +1,28 @@ /* * HvCall.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -//=========================================================================== -// -// This file contains the "hypervisor call" interface which is used to -// drive the hypervisor from the OS. -// -//=========================================================================== +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ #ifndef _HVCALL_H #define _HVCALL_H -//------------------------------------------------------------------- -// Standard Includes -//------------------------------------------------------------------- #include #include #include @@ -76,9 +70,9 @@ enum HvCall_VaryOffChunkRc */ /* Type of yield for HvCallBaseYieldProcessor */ -#define HvCall_YieldTimed 0 // Yield until specified time (tb) -#define HvCall_YieldToActive 1 // Yield until all active procs have run -#define HvCall_YieldToProc 2 // Yield until the specified processor has run +#define HvCall_YieldTimed 0 /* Yield until specified time (tb) */ +#define HvCall_YieldToActive 1 /* Yield until all active procs have run */ +#define HvCall_YieldToProc 2 /* Yield until the specified processor has run */ /* interrupt masks for setEnabledInterrupts */ #define HvCall_MaskIPI 0x00000001 @@ -86,7 +80,7 @@ enum HvCall_VaryOffChunkRc #define HvCall_MaskLpProd 0x00000004 #define HvCall_MaskTimeout 0x00000008 -/* Log buffer formats */ +/* Log buffer formats */ #define HvCall_LogBuffer_ASCII 0 #define HvCall_LogBuffer_EBCDIC 1 @@ -95,7 +89,7 @@ enum HvCall_VaryOffChunkRc #define HvCallBaseGetHwPatch HvCallBase + 2 #define HvCallBaseReIplSpAttn HvCallBase + 3 #define HvCallBaseSetASR HvCallBase + 4 -#define HvCallBaseSetASRAndRfi HvCallBase + 5 +#define HvCallBaseSetASRAndRfi HvCallBase + 5 #define HvCallBaseSetIMR HvCallBase + 6 #define HvCallBaseSendIPI HvCallBase + 7 #define HvCallBaseTerminateMachine HvCallBase + 8 @@ -115,81 +109,75 @@ enum HvCall_VaryOffChunkRc #define HvCallBaseGetLogBufferCodePage HvCallBase + 22 #define HvCallBaseGetLogBufferFormat HvCallBase + 23 #define HvCallBaseGetLogBufferLength HvCallBase + 24 -#define HvCallBaseReadLogBuffer HvCallBase + 25 +#define HvCallBaseReadLogBuffer HvCallBase + 25 #define HvCallBaseSetLogBufferFormatAndCodePage HvCallBase + 26 -#define HvCallBaseWriteLogBuffer HvCallBase + 27 +#define HvCallBaseWriteLogBuffer HvCallBase + 27 #define HvCallBaseRouter28 HvCallBase + 28 #define HvCallBaseRouter29 HvCallBase + 29 #define HvCallBaseRouter30 HvCallBase + 30 -#define HvCallBaseSetDebugBus HvCallBase + 31 +#define HvCallBaseSetDebugBus HvCallBase + 31 -#define HvCallCcSetDABR HvCallCc + 7 +#define HvCallCcSetDABR HvCallCc + 7 -//===================================================================================== -static inline void HvCall_setVirtualDecr(void) +static inline void HvCall_setVirtualDecr(void) { - /* Ignore any error return codes - most likely means that the target value for the - * LP has been increased and this vary off would bring us below the new target. */ + /* + * Ignore any error return codes - most likely means that the + * target value for the LP has been increased and this vary off + * would bring us below the new target. + */ HvCall0(HvCallBaseSetVirtualDecr); } -//===================================================================== -static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm) + +static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm) { - HvCall2( HvCallBaseYieldProcessor, typeOfYield, yieldParm ); + HvCall2(HvCallBaseYieldProcessor, typeOfYield, yieldParm); } -//===================================================================== -static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts) + +static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts) { - HvCall1(HvCallBaseSetEnabledInterrupts,enabledInterrupts); + HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts); } -//===================================================================== -static inline void HvCall_clearLogBuffer(HvLpIndex lpindex) +static inline void HvCall_clearLogBuffer(HvLpIndex lpindex) { - HvCall1(HvCallBaseClearLogBuffer,lpindex); + HvCall1(HvCallBaseClearLogBuffer, lpindex); } -//===================================================================== -static inline u32 HvCall_getLogBufferCodePage(HvLpIndex lpindex) +static inline u32 HvCall_getLogBufferCodePage(HvLpIndex lpindex) { - u32 retVal = HvCall1(HvCallBaseGetLogBufferCodePage,lpindex); + u32 retVal = HvCall1(HvCallBaseGetLogBufferCodePage, lpindex); return retVal; } -//===================================================================== -static inline int HvCall_getLogBufferFormat(HvLpIndex lpindex) +static inline int HvCall_getLogBufferFormat(HvLpIndex lpindex) { - int retVal = HvCall1(HvCallBaseGetLogBufferFormat,lpindex); + int retVal = HvCall1(HvCallBaseGetLogBufferFormat, lpindex); return retVal; } -//===================================================================== -static inline u32 HvCall_getLogBufferLength(HvLpIndex lpindex) +static inline u32 HvCall_getLogBufferLength(HvLpIndex lpindex) { - u32 retVal = HvCall1(HvCallBaseGetLogBufferLength,lpindex); + u32 retVal = HvCall1(HvCallBaseGetLogBufferLength, lpindex); return retVal; } -//===================================================================== -static inline void HvCall_setLogBufferFormatAndCodepage(int format, u32 codePage) +static inline void HvCall_setLogBufferFormatAndCodepage(int format, u32 codePage) { - HvCall2(HvCallBaseSetLogBufferFormatAndCodePage,format, codePage); + HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage); } -//===================================================================== -int HvCall_readLogBuffer(HvLpIndex lpindex, void *buffer, u64 bufLen); -void HvCall_writeLogBuffer(const void *buffer, u64 bufLen); +extern int HvCall_readLogBuffer(HvLpIndex lpindex, void *buffer, u64 bufLen); +extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen); -//===================================================================== -static inline void HvCall_sendIPI(struct paca_struct * targetPaca) +static inline void HvCall_sendIPI(struct paca_struct *targetPaca) { - HvCall1( HvCallBaseSendIPI, targetPaca->paca_index ); + HvCall1(HvCallBaseSendIPI, targetPaca->paca_index); } -//===================================================================== -static inline void HvCall_terminateMachineSrc(void) +static inline void HvCall_terminateMachineSrc(void) { - HvCall0( HvCallBaseTerminateMachineSrc ); + HvCall0(HvCallBaseTerminateMachineSrc); } static inline void HvCall_setDABR(unsigned long val) diff --git a/include/asm-ppc64/iSeries/HvCallCfg.h b/include/asm-ppc64/iSeries/HvCallCfg.h index 9f40f16..2223a96 100644 --- a/include/asm-ppc64/iSeries/HvCallCfg.h +++ b/include/asm-ppc64/iSeries/HvCallCfg.h @@ -1,43 +1,32 @@ /* * HvCallCfg.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -//===================================================================================== -// -// This file contains the "hypervisor call" interface which is used to -// drive the hypervisor from the OS. -// -//===================================================================================== +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ #ifndef _HVCALLCFG_H #define _HVCALLCFG_H -//------------------------------------------------------------------- -// Standard Includes -//------------------------------------------------------------------- #include #include -//------------------------------------------------------------------------------------- -// Constants -//------------------------------------------------------------------------------------- - -enum HvCallCfg_ReqQual -{ +enum HvCallCfg_ReqQual { HvCallCfg_Cur = 0, HvCallCfg_Init = 1, HvCallCfg_Max = 2, @@ -49,7 +38,7 @@ enum HvCallCfg_ReqQual #define HvCallCfgGetLpVrmIndex HvCallCfg + 2 #define HvCallCfgGetLpMinSupportedPlicVrmIndex HvCallCfg + 3 #define HvCallCfgGetLpMinCompatablePlicVrmIndex HvCallCfg + 4 -#define HvCallCfgGetLpVrmName HvCallCfg + 5 +#define HvCallCfgGetLpVrmName HvCallCfg + 5 #define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6 #define HvCallCfgGetPhysicalProcessors HvCallCfg + 7 #define HvCallCfgGetSystemMsChunks HvCallCfg + 8 @@ -76,108 +65,113 @@ enum HvCallCfg_ReqQual #define HvCallCfgSetMinRuntimeMsChunks HvCallCfg + 29 #define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30 #define HvCallCfgGetLpExecutionMode HvCallCfg + 31 -#define HvCallCfgGetHostingLpIndex HvCallCfg + 32 +#define HvCallCfgGetHostingLpIndex HvCallCfg + 32 -//==================================================================== static inline HvLpIndex HvCallCfg_getLps(void) { HvLpIndex retVal = HvCall0(HvCallCfgGetLps); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//==================================================================== -static inline int HvCallCfg_isBusDedicated(u64 busIndex) + +static inline int HvCallCfg_isBusDedicated(u64 busIndex) { int retVal = HvCall1(HvCallCfgIsBusDedicated,busIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//==================================================================== + static inline HvLpIndex HvCallCfg_getBusOwner(u64 busIndex) { HvLpIndex retVal = HvCall1(HvCallCfgGetBusOwner,busIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//==================================================================== -static inline HvLpIndexMap HvCallCfg_getBusAllocation(u64 busIndex) + +static inline HvLpIndexMap HvCallCfg_getBusAllocation(u64 busIndex) { HvLpIndexMap retVal = HvCall1(HvCallCfgGetBusAllocation,busIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//==================================================================== -static inline HvLpIndexMap HvCallCfg_getActiveLpMap(void) + +static inline HvLpIndexMap HvCallCfg_getActiveLpMap(void) { HvLpIndexMap retVal = HvCall0(HvCallCfgGetActiveLpMap); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//==================================================================== -static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap(HvLpIndex lp) + +static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap( + HvLpIndex lp) { - // This is a new function in V5R1 so calls to this on older - // hypervisors will return -1 + /* + * This is a new function in V5R1 so calls to this on older + * hypervisors will return -1 + */ u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp); - if(retVal == -1) + if (retVal == -1) retVal = 0; // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getSystemMsChunks(void) + +static inline u64 HvCallCfg_getSystemMsChunks(void) { u64 retVal = HvCall0(HvCallCfgGetSystemMsChunks); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getMsChunks(HvLpIndex lp,enum HvCallCfg_ReqQual qual) + +static inline u64 HvCallCfg_getMsChunks(HvLpIndex lp, + enum HvCallCfg_ReqQual qual) { u64 retVal = HvCall2(HvCallCfgGetMsChunks,lp,qual); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getMinRuntimeMsChunks(HvLpIndex lp) + +static inline u64 HvCallCfg_getMinRuntimeMsChunks(HvLpIndex lp) { - // NOTE: This function was added in v5r1 so older hypervisors will return a -1 value - u64 retVal = HvCall1(HvCallCfgGetMinRuntimeMsChunks,lp); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + /* + * NOTE: This function was added in v5r1 so older hypervisors + * will return a -1 value + */ + return HvCall1(HvCallCfgGetMinRuntimeMsChunks, lp); } -//=================================================================== -static inline u64 HvCallCfg_setMinRuntimeMsChunks(u64 chunks) + +static inline u64 HvCallCfg_setMinRuntimeMsChunks(u64 chunks) { u64 retVal = HvCall1(HvCallCfgSetMinRuntimeMsChunks,chunks); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getSystemPhysicalProcessors(void) + +static inline u64 HvCallCfg_getSystemPhysicalProcessors(void) { u64 retVal = HvCall0(HvCallCfgGetSystemPhysicalProcessors); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getPhysicalProcessors(HvLpIndex lp,enum HvCallCfg_ReqQual qual) + +static inline u64 HvCallCfg_getPhysicalProcessors(HvLpIndex lp, + enum HvCallCfg_ReqQual qual) { u64 retVal = HvCall2(HvCallCfgGetPhysicalProcessors,lp,qual); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//=================================================================== -static inline u64 HvCallCfg_getConfiguredBusUnitsForInterruptProc(HvLpIndex lp, - u16 hvLogicalProcIndex) + +static inline u64 HvCallCfg_getConfiguredBusUnitsForInterruptProc(HvLpIndex lp, + u16 hvLogicalProcIndex) { u64 retVal = HvCall2(HvCallCfgGetConfiguredBusUnitsForIntProc,lp,hvLogicalProcIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//================================================================== -static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp) + +static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp) { HvLpSharedPoolIndex retVal = HvCall1(HvCallCfgGetSharedPoolIndex,lp); @@ -185,29 +179,29 @@ static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp) return retVal; } -//================================================================== -static inline u64 HvCallCfg_getSharedProcUnits(HvLpIndex lp,enum HvCallCfg_ReqQual qual) + +static inline u64 HvCallCfg_getSharedProcUnits(HvLpIndex lp, + enum HvCallCfg_ReqQual qual) { u64 retVal = HvCall2(HvCallCfgGetSharedProcUnits,lp,qual); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//================================================================== -static inline u64 HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) + +static inline u64 HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) { u16 retVal = HvCall1(HvCallCfgGetNumProcsInSharedPool,sPI); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//================================================================== + static inline HvLpIndex HvCallCfg_getHostingLpIndex(HvLpIndex lp) { u64 retVal = HvCall1(HvCallCfgGetHostingLpIndex,lp); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; - } #endif /* _HVCALLCFG_H */ diff --git a/include/asm-ppc64/iSeries/HvCallEvent.h b/include/asm-ppc64/iSeries/HvCallEvent.h index 191ddce..a595478 100644 --- a/include/asm-ppc64/iSeries/HvCallEvent.h +++ b/include/asm-ppc64/iSeries/HvCallEvent.h @@ -1,32 +1,28 @@ /* * HvCallEvent.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - /* - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from the OS. + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. */ #ifndef _HVCALLEVENT_H #define _HVCALLEVENT_H -/* - * Standard Includes - */ #include #include #include @@ -71,7 +67,7 @@ typedef u64 HvLpDma_Rc; #define HvCallEventCloseLpEventPath HvCallEvent + 2 #define HvCallEventDmaBufList HvCallEvent + 3 #define HvCallEventDmaSingle HvCallEvent + 4 -#define HvCallEventDmaToSp HvCallEvent + 5 +#define HvCallEventDmaToSp HvCallEvent + 5 #define HvCallEventGetOverflowLpEvents HvCallEvent + 6 #define HvCallEventGetSourceLpInstanceId HvCallEvent + 7 #define HvCallEventGetTargetLpInstanceId HvCallEvent + 8 @@ -85,13 +81,13 @@ typedef u64 HvLpDma_Rc; static inline void HvCallEvent_getOverflowLpEvents(u8 queueIndex) { - HvCall1(HvCallEventGetOverflowLpEvents,queueIndex); + HvCall1(HvCallEventGetOverflowLpEvents, queueIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline void HvCallEvent_setInterLpQueueIndex(u8 queueIndex) { - HvCall1(HvCallEventSetInterLpQueueIndex,queueIndex); + HvCall1(HvCallEventSetInterLpQueueIndex, queueIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } @@ -138,7 +134,7 @@ static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp, { HvLpEvent_Rc retVal; - // Pack the misc bits into a single Dword to pass to PLIC + /* Pack the misc bits into a single Dword to pass to PLIC */ union { struct HvCallEvent_PackedParms parms; u64 dword; @@ -225,7 +221,7 @@ static inline HvLpDma_Rc HvCallEvent_dmaBufList(HvLpEvent_Type type, u64 localBufList, u64 remoteBufList, u32 transferLength) { HvLpDma_Rc retVal; - // Pack the misc bits into a single Dword to pass to PLIC + /* Pack the misc bits into a single Dword to pass to PLIC */ union { struct HvCallEvent_PackedDmaParms parms; u64 dword; @@ -257,7 +253,7 @@ static inline HvLpDma_Rc HvCallEvent_dmaSingle(HvLpEvent_Type type, u64 localAddrOrTce, u64 remoteAddrOrTce, u32 transferLength) { HvLpDma_Rc retVal; - // Pack the misc bits into a single Dword to pass to PLIC + /* Pack the misc bits into a single Dword to pass to PLIC */ union { struct HvCallEvent_PackedDmaParms parms; u64 dword; @@ -280,7 +276,7 @@ static inline HvLpDma_Rc HvCallEvent_dmaSingle(HvLpEvent_Type type, return retVal; } -static inline HvLpDma_Rc HvCallEvent_dmaToSp(void* local, u32 remote, +static inline HvLpDma_Rc HvCallEvent_dmaToSp(void *local, u32 remote, u32 length, HvLpDma_Direction dir) { u64 abs_addr; @@ -293,5 +289,4 @@ static inline HvLpDma_Rc HvCallEvent_dmaToSp(void* local, u32 remote, return retVal; } - #endif /* _HVCALLEVENT_H */ diff --git a/include/asm-ppc64/iSeries/HvCallHpt.h b/include/asm-ppc64/iSeries/HvCallHpt.h index da76987..827d26c 100644 --- a/include/asm-ppc64/iSeries/HvCallHpt.h +++ b/include/asm-ppc64/iSeries/HvCallHpt.h @@ -1,17 +1,17 @@ /* * HvCallHpt.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,21 +19,15 @@ #ifndef _HVCALLHPT_H #define _HVCALLHPT_H -//============================================================================ -// -// This file contains the "hypervisor call" interface which is used to -// drive the hypervisor from the OS. -// -//============================================================================ +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ #include #include #include -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- - #define HvCallHptGetHptAddress HvCallHpt + 0 #define HvCallHptGetHptPages HvCallHpt + 1 #define HvCallHptSetPp HvCallHpt + 5 @@ -47,81 +41,76 @@ #define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18 -//============================================================================ -static inline u64 HvCallHpt_getHptAddress(void) +static inline u64 HvCallHpt_getHptAddress(void) { u64 retval = HvCall0(HvCallHptGetHptAddress); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retval; } -//============================================================================ -static inline u64 HvCallHpt_getHptPages(void) -{ + +static inline u64 HvCallHpt_getHptPages(void) +{ u64 retval = HvCall0(HvCallHptGetHptPages); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retval; } -//============================================================================= -static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value) + +static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value) { - HvCall2( HvCallHptSetPp, hpteIndex, value ); + HvCall2(HvCallHptSetPp, hpteIndex, value); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } -//============================================================================= -static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff ) + +static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff) { - HvCall3( HvCallHptSetSwBits, hpteIndex, bitson, bitsoff ); + HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } -//============================================================================= -static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex) - + +static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex) { - HvCall1( HvCallHptInvalidateNoSyncICache, hpteIndex ); + HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } -//============================================================================= -static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, u8 bitsoff ) - + +static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, + u8 bitsoff) { u64 compressedStatus; - compressedStatus = HvCall4( HvCallHptInvalidateSetSwBitsGet, hpteIndex, bitson, bitsoff, 1 ); - HvCall1( HvCallHptInvalidateNoSyncICache, hpteIndex ); + + compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet, + hpteIndex, bitson, bitsoff, 1); + HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return compressedStatus; } -//============================================================================= -static inline u64 HvCallHpt_findValid( HPTE *hpte, u64 vpn ) + +static inline u64 HvCallHpt_findValid(HPTE *hpte, u64 vpn) { u64 retIndex = HvCall3Ret16( HvCallHptFindValid, hpte, vpn, 0, 0 ); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retIndex; } -//============================================================================= -static inline u64 HvCallHpt_findNextValid( HPTE *hpte, u32 hpteIndex, u8 bitson, u8 bitsoff ) + +static inline u64 HvCallHpt_findNextValid(HPTE *hpte, u32 hpteIndex, + u8 bitson, u8 bitsoff) { u64 retIndex = HvCall3Ret16( HvCallHptFindNextValid, hpte, hpteIndex, bitson, bitsoff ); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retIndex; } -//============================================================================= -static inline void HvCallHpt_get( HPTE *hpte, u32 hpteIndex ) + +static inline void HvCallHpt_get(HPTE *hpte, u32 hpteIndex) { - HvCall2Ret16( HvCallHptGet, hpte, hpteIndex, 0 ); + HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } -//============================================================================ -static inline void HvCallHpt_addValidate( u32 hpteIndex, - u32 hBit, - HPTE *hpte ) - + +static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, HPTE *hpte) { - HvCall4( HvCallHptAddValidate, hpteIndex, - hBit, (*((u64 *)hpte)), (*(((u64 *)hpte)+1)) ); + HvCall4(HvCallHptAddValidate, hpteIndex, hBit, (*((u64 *)hpte)), + (*(((u64 *)hpte)+1))); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } - -//============================================================================= - #endif /* _HVCALLHPT_H */ diff --git a/include/asm-ppc64/iSeries/HvCallPci.h b/include/asm-ppc64/iSeries/HvCallPci.h index 6887b61..346ab5d 100644 --- a/include/asm-ppc64/iSeries/HvCallPci.h +++ b/include/asm-ppc64/iSeries/HvCallPci.h @@ -1,26 +1,26 @@ -/************************************************************************/ -/* Provides the Hypervisor PCI calls for iSeries Linux Parition. */ -/* Copyright (C) 2001 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that 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., */ -/* 59 Temple Place, Suite 330, */ -/* Boston, MA 02111-1307 USA */ -/************************************************************************/ -/* Change Activity: */ -/* Created, Jan 9, 2001 */ -/************************************************************************/ +/* + * Provides the Hypervisor PCI calls for iSeries Linux Parition. + * Copyright (C) 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * Change Activity: + * Created, Jan 9, 2001 + */ #ifndef _HVCALLPCI_H #define _HVCALLPCI_H @@ -34,8 +34,8 @@ */ struct HvCallPci_DsaAddr { u16 busNumber; /* PHB index? */ - u8 subBusNumber; /* PCI bus number? */ - u8 deviceId; /* device and function? */ + u8 subBusNumber; /* PCI bus number? */ + u8 deviceId; /* device and function? */ u8 barNumber; u8 reserved[3]; }; @@ -52,34 +52,37 @@ struct HvCallPci_LoadReturn { enum HvCallPci_DeviceType { HvCallPci_NodeDevice = 1, - HvCallPci_SpDevice = 2, - HvCallPci_IopDevice = 3, - HvCallPci_BridgeDevice = 4, - HvCallPci_MultiFunctionDevice = 5, - HvCallPci_IoaDevice = 6 + HvCallPci_SpDevice = 2, + HvCallPci_IopDevice = 3, + HvCallPci_BridgeDevice = 4, + HvCallPci_MultiFunctionDevice = 5, + HvCallPci_IoaDevice = 6 }; struct HvCallPci_DeviceInfo { - u32 deviceType; // See DeviceType enum for values + u32 deviceType; /* See DeviceType enum for values */ }; - + struct HvCallPci_BusUnitInfo { - u32 sizeReturned; // length of data returned - u32 deviceType; // see DeviceType enum for values + u32 sizeReturned; /* length of data returned */ + u32 deviceType; /* see DeviceType enum for values */ }; struct HvCallPci_BridgeInfo { - struct HvCallPci_BusUnitInfo busUnitInfo; // Generic bus unit info - u8 subBusNumber; // Bus number of secondary bus - u8 maxAgents; // Max idsels on secondary bus - u8 maxSubBusNumber; // Max Sub Bus - u8 logicalSlotNumber; // Logical Slot Number for IOA + struct HvCallPci_BusUnitInfo busUnitInfo; /* Generic bus unit info */ + u8 subBusNumber; /* Bus number of secondary bus */ + u8 maxAgents; /* Max idsels on secondary bus */ + u8 maxSubBusNumber; /* Max Sub Bus */ + u8 logicalSlotNumber; /* Logical Slot Number for IOA */ }; - -// Maximum BusUnitInfo buffer size. Provided for clients so they can allocate -// a buffer big enough for any type of bus unit. Increase as needed. + +/* + * Maximum BusUnitInfo buffer size. Provided for clients so + * they can allocate a buffer big enough for any type of bus + * unit. Increase as needed. + */ enum {HvCallPci_MaxBusUnitInfoSize = 128}; struct HvCallPci_BarParms { @@ -89,12 +92,12 @@ struct HvCallPci_BarParms { u64 protectStart; u64 protectEnd; u64 relocationOffset; - u64 pciAddress; + u64 pciAddress; u64 reserved[3]; -}; +}; enum HvCallPci_VpdType { - HvCallPci_BusVpd = 1, + HvCallPci_BusVpd = 1, HvCallPci_BusAdapterVpd = 2 }; @@ -123,15 +126,13 @@ enum HvCallPci_VpdType { #define HvCallPciUnmaskInterrupts HvCallPci + 49 #define HvCallPciGetBusUnitInfo HvCallPci + 50 -//============================================================================ static inline u64 HvCallPci_configLoad8(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u8 *value) + u8 deviceId, u32 offset, u8 *value) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -145,15 +146,14 @@ static inline u64 HvCallPci_configLoad8(u16 busNumber, u8 subBusNumber, return retVal.rc; } -//============================================================================ + static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u16 *value) + u8 deviceId, u32 offset, u16 *value) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -167,15 +167,14 @@ static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber, return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u32 *value) + +static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u32 *value) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -189,15 +188,14 @@ static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u8 value) + +static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u8 value) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -209,15 +207,14 @@ static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, return retVal; } -//============================================================================ -static inline u64 HvCallPci_configStore16(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u16 value) + +static inline u64 HvCallPci_configStore16(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u16 value) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -229,15 +226,14 @@ static inline u64 HvCallPci_configStore16(u16 busNumber, u8 subBusNumber, return retVal; } -//============================================================================ -static inline u64 HvCallPci_configStore32(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, - u32 value) + +static inline u64 HvCallPci_configStore32(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u32 value) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumber; dsa.subBusNumber = subBusNumber; @@ -249,18 +245,15 @@ static inline u64 HvCallPci_configStore32(u16 busNumber, u8 subBusNumber, return retVal; } -//============================================================================ -static inline u64 HvCallPci_barLoad8(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u8* valueParm) + +static inline u64 HvCallPci_barLoad8(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u8 *valueParm) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -275,18 +268,15 @@ static inline u64 HvCallPci_barLoad8(u16 busNumberParm, return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_barLoad16(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u16* valueParm) + +static inline u64 HvCallPci_barLoad16(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u16 *valueParm) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -301,18 +291,15 @@ static inline u64 HvCallPci_barLoad16(u16 busNumberParm, return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_barLoad32(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u32* valueParm) + +static inline u64 HvCallPci_barLoad32(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u32 *valueParm) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -327,18 +314,15 @@ static inline u64 HvCallPci_barLoad32(u16 busNumberParm, return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_barLoad64(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u64* valueParm) + +static inline u64 HvCallPci_barLoad64(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u64 *valueParm) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -353,19 +337,16 @@ static inline u64 HvCallPci_barLoad64(u16 busNumberParm, return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_barStore8(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u8 valueParm) + +static inline u64 HvCallPci_barStore8(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u8 valueParm) { struct HvCallPci_DsaAddr dsa; u64 retVal; *((u64*)&dsa) = 0; - + dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; @@ -377,19 +358,16 @@ static inline u64 HvCallPci_barStore8(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_barStore16(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u16 valueParm) + +static inline u64 HvCallPci_barStore16(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u16 valueParm) { struct HvCallPci_DsaAddr dsa; u64 retVal; *((u64*)&dsa) = 0; - + dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; @@ -401,19 +379,16 @@ static inline u64 HvCallPci_barStore16(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_barStore32(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u32 valueParm) + +static inline u64 HvCallPci_barStore32(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u32 valueParm) { struct HvCallPci_DsaAddr dsa; u64 retVal; *((u64*)&dsa) = 0; - + dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; @@ -425,19 +400,16 @@ static inline u64 HvCallPci_barStore32(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_barStore64(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 offsetParm, - u64 valueParm) + +static inline u64 HvCallPci_barStore64(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 offsetParm, + u64 valueParm) { struct HvCallPci_DsaAddr dsa; u64 retVal; *((u64*)&dsa) = 0; - + dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; @@ -449,10 +421,9 @@ static inline u64 HvCallPci_barStore64(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_eoi(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm) + +static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm) { struct HvCallPci_DsaAddr dsa; struct HvCallPci_LoadReturn retVal; @@ -469,13 +440,9 @@ static inline u64 HvCallPci_eoi(u16 busNumberParm, return retVal.rc; } -//============================================================================ -static inline u64 HvCallPci_getBarParms(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u8 barNumberParm, - u64 parms, - u32 sizeofParms) + +static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms) { struct HvCallPci_DsaAddr dsa; u64 retVal; @@ -493,16 +460,14 @@ static inline u64 HvCallPci_getBarParms(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_maskFisr(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 fisrMask) + +static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 fisrMask) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -514,16 +479,14 @@ static inline u64 HvCallPci_maskFisr(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 fisrMask) + +static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 fisrMask) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -535,11 +498,9 @@ static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_setSlotReset(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 onNotOff) + +static inline u64 HvCallPci_setSlotReset(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 onNotOff) { struct HvCallPci_DsaAddr dsa; u64 retVal; @@ -556,12 +517,9 @@ static inline u64 HvCallPci_setSlotReset(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, - u8 subBusParm, - u8 deviceNumberParm, - u64 parms, - u32 sizeofParms) + +static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm, + u8 deviceNumberParm, u64 parms, u32 sizeofParms) { struct HvCallPci_DsaAddr dsa; u64 retVal; @@ -578,16 +536,14 @@ static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 interruptMask) + +static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 interruptMask) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -599,16 +555,14 @@ static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 interruptMask) + +static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 interruptMask) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -620,18 +574,14 @@ static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, return retVal; } -//============================================================================ -static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, - u8 subBusParm, - u8 deviceIdParm, - u64 parms, - u32 sizeofParms) +static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 parms, u32 sizeofParms) { struct HvCallPci_DsaAddr dsa; u64 retVal; - *((u64*)&dsa) = 0; + *((u64*)&dsa) = 0; dsa.busNumber = busNumberParm; dsa.subBusNumber = subBusParm; @@ -643,9 +593,9 @@ static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, return retVal; } -//============================================================================ -static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, u16 sizeParm) +static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, + u16 sizeParm) { int xRetSize; u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, sizeParm, HvCallPci_BusVpd); @@ -656,9 +606,9 @@ static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, u16 sizeParm xRetSize = xRc & 0xFFFF; return xRetSize; } -//============================================================================ -static inline int HvCallPci_getBusAdapterVpd(u16 busNumParm, u64 destParm, u16 sizeParm) +static inline int HvCallPci_getBusAdapterVpd(u16 busNumParm, u64 destParm, + u16 sizeParm) { int xRetSize; u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, sizeParm, HvCallPci_BusAdapterVpd); @@ -669,5 +619,5 @@ static inline int HvCallPci_getBusAdapterVpd(u16 busNumParm, u64 destParm, u16 s xRetSize = xRc & 0xFFFF; return xRetSize; } -//============================================================================ + #endif /* _HVCALLPCI_H */ diff --git a/include/asm-ppc64/iSeries/HvCallSc.h b/include/asm-ppc64/iSeries/HvCallSc.h index eea2584..c32145f 100644 --- a/include/asm-ppc64/iSeries/HvCallSc.h +++ b/include/asm-ppc64/iSeries/HvCallSc.h @@ -1,17 +1,17 @@ /* * HvCallSc.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -30,22 +30,22 @@ #define HvCallSm 0x8007000000000000ul #define HvCallXm 0x8009000000000000ul -u64 HvCall0( u64 ); -u64 HvCall1( u64, u64 ); -u64 HvCall2( u64, u64, u64 ); -u64 HvCall3( u64, u64, u64, u64 ); -u64 HvCall4( u64, u64, u64, u64, u64 ); -u64 HvCall5( u64, u64, u64, u64, u64, u64 ); -u64 HvCall6( u64, u64, u64, u64, u64, u64, u64 ); -u64 HvCall7( u64, u64, u64, u64, u64, u64, u64, u64 ); +u64 HvCall0(u64); +u64 HvCall1(u64, u64); +u64 HvCall2(u64, u64, u64); +u64 HvCall3(u64, u64, u64, u64); +u64 HvCall4(u64, u64, u64, u64, u64); +u64 HvCall5(u64, u64, u64, u64, u64, u64); +u64 HvCall6(u64, u64, u64, u64, u64, u64, u64); +u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64); -u64 HvCall0Ret16( u64, void * ); -u64 HvCall1Ret16( u64, void *, u64 ); -u64 HvCall2Ret16( u64, void *, u64, u64 ); -u64 HvCall3Ret16( u64, void *, u64, u64, u64 ); -u64 HvCall4Ret16( u64, void *, u64, u64, u64, u64 ); -u64 HvCall5Ret16( u64, void *, u64, u64, u64, u64, u64 ); -u64 HvCall6Ret16( u64, void *, u64, u64, u64, u64, u64, u64 ); -u64 HvCall7Ret16( u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64 ); +u64 HvCall0Ret16(u64, void *); +u64 HvCall1Ret16(u64, void *, u64); +u64 HvCall2Ret16(u64, void *, u64, u64); +u64 HvCall3Ret16(u64, void *, u64, u64, u64); +u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64); +u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64); +u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64); +u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64); #endif /* _HVCALLSC_H */ diff --git a/include/asm-ppc64/iSeries/HvCallSm.h b/include/asm-ppc64/iSeries/HvCallSm.h index 9050c94..ef6b303 100644 --- a/include/asm-ppc64/iSeries/HvCallSm.h +++ b/include/asm-ppc64/iSeries/HvCallSm.h @@ -1,17 +1,17 @@ /* * HvCallSm.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,34 +19,23 @@ #ifndef _HVCALLSM_H #define _HVCALLSM_H -//============================================================================ -// -// This file contains the "hypervisor call" interface which is used to -// drive the hypervisor from the OS. -// -//============================================================================ +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ -//------------------------------------------------------------------- -// Standard Includes -//------------------------------------------------------------------- #include #include -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- - #define HvCallSmGet64BitsOfAccessMap HvCallSm + 11 - -//============================================================================ -static inline u64 HvCallSm_get64BitsOfAccessMap( - HvLpIndex lpIndex, u64 indexIntoBitMap ) +static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex, + u64 indexIntoBitMap) { u64 retval = HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap ); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retval; } -//============================================================================ + #endif /* _HVCALLSM_H */ diff --git a/include/asm-ppc64/iSeries/HvCallXm.h b/include/asm-ppc64/iSeries/HvCallXm.h index bfb898f..a99f29b 100644 --- a/include/asm-ppc64/iSeries/HvCallXm.h +++ b/include/asm-ppc64/iSeries/HvCallXm.h @@ -1,30 +1,13 @@ -//============================================================================ -// Header File Id -// Name______________: HvCallXm.H -// -// Description_______: -// -// This file contains the "hypervisor call" interface which is used to -// drive the hypervisor from SLIC. -// -//============================================================================ +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from SLIC. + */ #ifndef _HVCALLXM_H #define _HVCALLXM_H -//------------------------------------------------------------------- -// Forward declarations -//------------------------------------------------------------------- - -//------------------------------------------------------------------- -// Standard Includes -//------------------------------------------------------------------- #include #include -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- - #define HvCallXmGetTceTableParms HvCallXm + 0 #define HvCallXmTestBus HvCallXm + 1 #define HvCallXmConnectBusUnit HvCallXm + 2 @@ -33,47 +16,46 @@ #define HvCallXmSetTce HvCallXm + 11 #define HvCallXmSetTces HvCallXm + 13 - - -//============================================================================ -static inline void HvCallXm_getTceTableParms(u64 cb) +static inline void HvCallXm_getTceTableParms(u64 cb) { HvCall1(HvCallXmGetTceTableParms, cb); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } -//============================================================================ -static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce) -{ + +static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce) +{ u64 retval = HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce ); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retval; } -//============================================================================ -static inline u64 HvCallXm_setTces(u64 tceTableToken, u64 tceOffset, u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4) -{ + +static inline u64 HvCallXm_setTces(u64 tceTableToken, u64 tceOffset, + u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4) +{ u64 retval = HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces, tce1, tce2, tce3, tce4 ); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retval; } -//============================================================================= -static inline u64 HvCallXm_testBus(u16 busNumber) + +static inline u64 HvCallXm_testBus(u16 busNumber) { u64 retVal = HvCall1(HvCallXmTestBus, busNumber); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//===================================================================================== -static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber, u8 deviceId) + +static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber, + u8 deviceId) { u64 busUnitNumber = (subBusNumber << 8) | deviceId; u64 retVal = HvCall2(HvCallXmTestBusUnit, busNumber, busUnitNumber); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//===================================================================================== -static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber, u8 deviceId, - u64 interruptToken) + +static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber, + u8 deviceId, u64 interruptToken) { u64 busUnitNumber = (subBusNumber << 8) | deviceId; u64 queueIndex = 0; // HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard)); @@ -83,13 +65,12 @@ static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber, u8 dev // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//===================================================================================== -static inline u64 HvCallXm_loadTod(void) + +static inline u64 HvCallXm_loadTod(void) { u64 retVal = HvCall0(HvCallXmLoadTod); // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } -//===================================================================================== #endif /* _HVCALLXM_H */ diff --git a/include/asm-ppc64/iSeries/HvLpConfig.h b/include/asm-ppc64/iSeries/HvLpConfig.h index bdbd70f..47311cc 100644 --- a/include/asm-ppc64/iSeries/HvLpConfig.h +++ b/include/asm-ppc64/iSeries/HvLpConfig.h @@ -1,17 +1,17 @@ /* * HvLpConfig.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,262 +19,285 @@ #ifndef _HVLPCONFIG_H #define _HVLPCONFIG_H -//=========================================================================== -// -// This file contains the interface to the LPAR configuration data -// to determine which resources should be allocated to each partition. -// -//=========================================================================== +/* + * This file contains the interface to the LPAR configuration data + * to determine which resources should be allocated to each partition. + */ #include #include #include #include -//------------------------------------------------------------------- -// Constants -//------------------------------------------------------------------- - extern HvLpIndex HvLpConfig_getLpIndex_outline(void); -//=================================================================== static inline HvLpIndex HvLpConfig_getLpIndex(void) { return itLpNaca.xLpIndex; } -//=================================================================== + static inline HvLpIndex HvLpConfig_getPrimaryLpIndex(void) { return itLpNaca.xPrimaryLpIndex; } -//================================================================= + static inline HvLpIndex HvLpConfig_getLps(void) { return HvCallCfg_getLps(); } -//================================================================= -static inline HvLpIndexMap HvLpConfig_getActiveLpMap(void) + +static inline HvLpIndexMap HvLpConfig_getActiveLpMap(void) { return HvCallCfg_getActiveLpMap(); } -//================================================================= -static inline u64 HvLpConfig_getSystemMsMegs(void) + +static inline u64 HvLpConfig_getSystemMsMegs(void) { return HvCallCfg_getSystemMsChunks() / HVCHUNKSPERMEG; } -//================================================================= -static inline u64 HvLpConfig_getSystemMsChunks(void) + +static inline u64 HvLpConfig_getSystemMsChunks(void) { return HvCallCfg_getSystemMsChunks(); } -//================================================================= -static inline u64 HvLpConfig_getSystemMsPages(void) + +static inline u64 HvLpConfig_getSystemMsPages(void) { return HvCallCfg_getSystemMsChunks() * HVPAGESPERCHUNK; } -//================================================================ -static inline u64 HvLpConfig_getMsMegs(void) + +static inline u64 HvLpConfig_getMsMegs(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Cur) / HVCHUNKSPERMEG; + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur) + / HVCHUNKSPERMEG; } -//================================================================ -static inline u64 HvLpConfig_getMsChunks(void) + +static inline u64 HvLpConfig_getMsChunks(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Cur); + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur); } -//================================================================ -static inline u64 HvLpConfig_getMsPages(void) + +static inline u64 HvLpConfig_getMsPages(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Cur) * HVPAGESPERCHUNK; + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur) + * HVPAGESPERCHUNK; } -//================================================================ -static inline u64 HvLpConfig_getMinMsMegs(void) + +static inline u64 HvLpConfig_getMinMsMegs(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Min) / HVCHUNKSPERMEG; + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Min) + / HVCHUNKSPERMEG; } -//================================================================ -static inline u64 HvLpConfig_getMinMsChunks(void) + +static inline u64 HvLpConfig_getMinMsChunks(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Min); + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Min); } -//================================================================ -static inline u64 HvLpConfig_getMinMsPages(void) + +static inline u64 HvLpConfig_getMinMsPages(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Min) * HVPAGESPERCHUNK; + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Min) + * HVPAGESPERCHUNK; } -//================================================================ -static inline u64 HvLpConfig_getMinRuntimeMsMegs(void) + +static inline u64 HvLpConfig_getMinRuntimeMsMegs(void) { - return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) / HVCHUNKSPERMEG; + return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) + / HVCHUNKSPERMEG; } -//=============================================================== -static inline u64 HvLpConfig_getMinRuntimeMsChunks(void) + +static inline u64 HvLpConfig_getMinRuntimeMsChunks(void) { return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()); } -//=============================================================== -static inline u64 HvLpConfig_getMinRuntimeMsPages(void) + +static inline u64 HvLpConfig_getMinRuntimeMsPages(void) { - return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) * HVPAGESPERCHUNK; + return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) + * HVPAGESPERCHUNK; } -//=============================================================== -static inline u64 HvLpConfig_getMaxMsMegs(void) + +static inline u64 HvLpConfig_getMaxMsMegs(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Max) / HVCHUNKSPERMEG; + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Max) + / HVCHUNKSPERMEG; } -//=============================================================== -static inline u64 HvLpConfig_getMaxMsChunks(void) + +static inline u64 HvLpConfig_getMaxMsChunks(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Max); + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Max); } -//=============================================================== -static inline u64 HvLpConfig_getMaxMsPages(void) + +static inline u64 HvLpConfig_getMaxMsPages(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Max) * HVPAGESPERCHUNK; + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Max) + * HVPAGESPERCHUNK; } -//=============================================================== -static inline u64 HvLpConfig_getInitMsMegs(void) + +static inline u64 HvLpConfig_getInitMsMegs(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Init) / HVCHUNKSPERMEG; + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Init) + / HVCHUNKSPERMEG; } -//=============================================================== -static inline u64 HvLpConfig_getInitMsChunks(void) + +static inline u64 HvLpConfig_getInitMsChunks(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Init); + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Init); } -//=============================================================== -static inline u64 HvLpConfig_getInitMsPages(void) -{ return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(),HvCallCfg_Init) * HVPAGESPERCHUNK; + +static inline u64 HvLpConfig_getInitMsPages(void) +{ + return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Init) + * HVPAGESPERCHUNK; } -//=============================================================== -static inline u64 HvLpConfig_getSystemPhysicalProcessors(void) + +static inline u64 HvLpConfig_getSystemPhysicalProcessors(void) { return HvCallCfg_getSystemPhysicalProcessors(); } -//=============================================================== -static inline u64 HvLpConfig_getSystemLogicalProcessors(void) + +static inline u64 HvLpConfig_getSystemLogicalProcessors(void) { - return HvCallCfg_getSystemPhysicalProcessors() * (/*getPaca()->getSecondaryThreadCount() +*/ 1); + return HvCallCfg_getSystemPhysicalProcessors() + * (/*getPaca()->getSecondaryThreadCount() +*/ 1); } -//=============================================================== -static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) + +static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) { return HvCallCfg_getNumProcsInSharedPool(sPI); } -//=============================================================== -static inline u64 HvLpConfig_getPhysicalProcessors(void) + +static inline u64 HvLpConfig_getPhysicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Cur); + return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + HvCallCfg_Cur); } -//=============================================================== -static inline u64 HvLpConfig_getLogicalProcessors(void) + +static inline u64 HvLpConfig_getLogicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Cur) * (/*getPaca()->getSecondaryThreadCount() +*/ 1); + return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + HvCallCfg_Cur) + * (/*getPaca()->getSecondaryThreadCount() +*/ 1); } -//=============================================================== -static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void) + +static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void) { return HvCallCfg_getSharedPoolIndex(HvLpConfig_getLpIndex()); } -//=============================================================== -static inline u64 HvLpConfig_getSharedProcUnits(void) + +static inline u64 HvLpConfig_getSharedProcUnits(void) { - return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(),HvCallCfg_Cur); + return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), + HvCallCfg_Cur); } -//=============================================================== -static inline u64 HvLpConfig_getMinSharedProcUnits(void) + +static inline u64 HvLpConfig_getMinSharedProcUnits(void) { - return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(),HvCallCfg_Min); + return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), + HvCallCfg_Min); } -//=============================================================== -static inline u64 HvLpConfig_getMaxSharedProcUnits(void) + +static inline u64 HvLpConfig_getMaxSharedProcUnits(void) { - return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(),HvCallCfg_Max); + return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), + HvCallCfg_Max); } -//=============================================================== -static inline u64 HvLpConfig_getMinPhysicalProcessors(void) + +static inline u64 HvLpConfig_getMinPhysicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Min); + return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + HvCallCfg_Min); } -//=============================================================== -static inline u64 HvLpConfig_getMinLogicalProcessors(void) + +static inline u64 HvLpConfig_getMinLogicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Min) * (/*getPaca()->getSecondaryThreadCount() +*/ 1); + return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + HvCallCfg_Min) + * (/*getPaca()->getSecondaryThreadCount() +*/ 1); } -//=============================================================== -static inline u64 HvLpConfig_getMaxPhysicalProcessors(void) + +static inline u64 HvLpConfig_getMaxPhysicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Max); + return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + HvCallCfg_Max); } -//=============================================================== -static inline u64 HvLpConfig_getMaxLogicalProcessors(void) + +static inline u64 HvLpConfig_getMaxLogicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Max) * (/*getPaca()->getSecondaryThreadCount() +*/ 1); + return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + HvCallCfg_Max) + * (/*getPaca()->getSecondaryThreadCount() +*/ 1); } -//=============================================================== -static inline u64 HvLpConfig_getInitPhysicalProcessors(void) + +static inline u64 HvLpConfig_getInitPhysicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Init); + return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + HvCallCfg_Init); } -//=============================================================== -static inline u64 HvLpConfig_getInitLogicalProcessors(void) + +static inline u64 HvLpConfig_getInitLogicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(),HvCallCfg_Init) * (/*getPaca()->getSecondaryThreadCount() +*/ 1); + return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + HvCallCfg_Init) + * (/*getPaca()->getSecondaryThreadCount() +*/ 1); } -//================================================================ -static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) + +static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) { return HvCallCfg_getVirtualLanIndexMap(HvLpConfig_getLpIndex_outline()); } -//=============================================================== -static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp(HvLpIndex lp) + +static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp( + HvLpIndex lp) { return HvCallCfg_getVirtualLanIndexMap(lp); } -//================================================================ -static inline HvLpIndex HvLpConfig_getBusOwner(HvBusNumber busNumber) + +static inline HvLpIndex HvLpConfig_getBusOwner(HvBusNumber busNumber) { return HvCallCfg_getBusOwner(busNumber); } -//=============================================================== -static inline int HvLpConfig_isBusDedicated(HvBusNumber busNumber) + +static inline int HvLpConfig_isBusDedicated(HvBusNumber busNumber) { return HvCallCfg_isBusDedicated(busNumber); } -//================================================================ -static inline HvLpIndexMap HvLpConfig_getBusAllocation(HvBusNumber busNumber) + +static inline HvLpIndexMap HvLpConfig_getBusAllocation(HvBusNumber busNumber) { return HvCallCfg_getBusAllocation(busNumber); } -//================================================================ -// returns the absolute real address of the load area -static inline u64 HvLpConfig_getLoadAddress(void) + +/* returns the absolute real address of the load area */ +static inline u64 HvLpConfig_getLoadAddress(void) { return itLpNaca.xLoadAreaAddr & 0x7fffffffffffffff; } -//================================================================ -static inline u64 HvLpConfig_getLoadPages(void) + +static inline u64 HvLpConfig_getLoadPages(void) { return itLpNaca.xLoadAreaChunks * HVPAGESPERCHUNK; } -//================================================================ -static inline int HvLpConfig_isBusOwnedByThisLp(HvBusNumber busNumber) + +static inline int HvLpConfig_isBusOwnedByThisLp(HvBusNumber busNumber) { HvLpIndex busOwner = HvLpConfig_getBusOwner(busNumber); return (busOwner == HvLpConfig_getLpIndex()); } -//================================================================ -static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, HvLpIndex lp2) + +static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, + HvLpIndex lp2) { - HvLpVirtualLanIndexMap virtualLanIndexMap1 = HvCallCfg_getVirtualLanIndexMap( lp1 ); - HvLpVirtualLanIndexMap virtualLanIndexMap2 = HvCallCfg_getVirtualLanIndexMap( lp2 ); + HvLpVirtualLanIndexMap virtualLanIndexMap1 = + HvCallCfg_getVirtualLanIndexMap(lp1); + HvLpVirtualLanIndexMap virtualLanIndexMap2 = + HvCallCfg_getVirtualLanIndexMap(lp2); return ((virtualLanIndexMap1 & virtualLanIndexMap2) != 0); } -//================================================================ -static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp) + +static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp) { return HvCallCfg_getHostingLpIndex(lp); } -//================================================================ #endif /* _HVLPCONFIG_H */ diff --git a/include/asm-ppc64/iSeries/HvLpEvent.h b/include/asm-ppc64/iSeries/HvLpEvent.h index 30936e43..865000d 100644 --- a/include/asm-ppc64/iSeries/HvLpEvent.h +++ b/include/asm-ppc64/iSeries/HvLpEvent.h @@ -1,27 +1,24 @@ /* * HvLpEvent.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -//====================================================================== -// -// This file contains the class for HV events in the system. -// -//===================================================================== +/* This file contains the class for HV events in the system. */ + #ifndef _HVLPEVENT_H #define _HVLPEVENT_H @@ -30,69 +27,70 @@ #include #include -//===================================================================== -// -// HvLpEvent is the structure for Lp Event messages passed between -// partitions through PLIC. -// -//===================================================================== - -struct HvEventFlags -{ - u8 xValid:1; // Indicates a valid request x00-x00 - u8 xRsvd1:4; // Reserved ... - u8 xAckType:1; // Immediate or deferred ... - u8 xAckInd:1; // Indicates if ACK required ... - u8 xFunction:1; // Interrupt or Acknowledge ... +/* + * HvLpEvent is the structure for Lp Event messages passed between + * partitions through PLIC. + */ + +struct HvEventFlags { + u8 xValid:1; /* Indicates a valid request x00-x00 */ + u8 xRsvd1:4; /* Reserved ... */ + u8 xAckType:1; /* Immediate or deferred ... */ + u8 xAckInd:1; /* Indicates if ACK required ... */ + u8 xFunction:1; /* Interrupt or Acknowledge ... */ }; -struct HvLpEvent -{ - struct HvEventFlags xFlags; // Event flags x00-x00 - u8 xType; // Type of message x01-x01 - u16 xSubtype; // Subtype for event x02-x03 - u8 xSourceLp; // Source LP x04-x04 - u8 xTargetLp; // Target LP x05-x05 - u8 xSizeMinus1; // Size of Derived class - 1 x06-x06 - u8 xRc; // RC for Ack flows x07-x07 - u16 xSourceInstanceId; // Source sides instance id x08-x09 - u16 xTargetInstanceId; // Target sides instance id x0A-x0B +struct HvLpEvent { + struct HvEventFlags xFlags; /* Event flags x00-x00 */ + u8 xType; /* Type of message x01-x01 */ + u16 xSubtype; /* Subtype for event x02-x03 */ + u8 xSourceLp; /* Source LP x04-x04 */ + u8 xTargetLp; /* Target LP x05-x05 */ + u8 xSizeMinus1; /* Size of Derived class - 1 x06-x06 */ + u8 xRc; /* RC for Ack flows x07-x07 */ + u16 xSourceInstanceId; /* Source sides instance id x08-x09 */ + u16 xTargetInstanceId; /* Target sides instance id x0A-x0B */ union { - u32 xSubtypeData; // Data usable by the subtype x0C-x0F - u16 xSubtypeDataShort[2]; // Data as 2 shorts - u8 xSubtypeDataChar[4]; // Data as 4 chars + u32 xSubtypeData; /* Data usable by the subtype x0C-x0F */ + u16 xSubtypeDataShort[2]; /* Data as 2 shorts */ + u8 xSubtypeDataChar[4]; /* Data as 4 chars */ } x; - u64 xCorrelationToken; // Unique value for source/type x10-x17 + u64 xCorrelationToken; /* Unique value for source/type x10-x17 */ }; -// Lp Event handler function typedef void (*LpEventHandler)(struct HvLpEvent *, struct pt_regs *); -// Register a handler for an event type -// returns 0 on success -extern int HvLpEvent_registerHandler( HvLpEvent_Type eventType, LpEventHandler hdlr); - -// Unregister a handler for an event type -// This call will sleep until the handler being removed is guaranteed to -// be no longer executing on any CPU. Do not call with locks held. -// -// returns 0 on success -// Unregister will fail if there are any paths open for the type -extern int HvLpEvent_unregisterHandler( HvLpEvent_Type eventType ); +/* Register a handler for an event type - returns 0 on success */ +extern int HvLpEvent_registerHandler(HvLpEvent_Type eventType, + LpEventHandler hdlr); -// Open an Lp Event Path for an event type -// returns 0 on success -// openPath will fail if there is no handler registered for the event type. -// The lpIndex specified is the partition index for the target partition -// (for VirtualIo, VirtualLan and SessionMgr) other types specify zero) -extern int HvLpEvent_openPath( HvLpEvent_Type eventType, HvLpIndex lpIndex ); +/* + * Unregister a handler for an event type + * + * This call will sleep until the handler being removed is guaranteed to + * be no longer executing on any CPU. Do not call with locks held. + * + * returns 0 on success + * Unregister will fail if there are any paths open for the type + */ +extern int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType); +/* + * Open an Lp Event Path for an event type + * returns 0 on success + * openPath will fail if there is no handler registered for the event type. + * The lpIndex specified is the partition index for the target partition + * (for VirtualIo, VirtualLan and SessionMgr) other types specify zero) + */ +extern int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex); -// Close an Lp Event Path for a type and partition -// returns 0 on sucess -extern int HvLpEvent_closePath( HvLpEvent_Type eventType, HvLpIndex lpIndex ); +/* + * Close an Lp Event Path for a type and partition + * returns 0 on sucess + */ +extern int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex); #define HvLpEvent_Type_Hypervisor 0 #define HvLpEvent_Type_MachineFac 1 @@ -141,4 +139,4 @@ extern int HvLpEvent_closePath( HvLpEvent_Type eventType, HvLpIndex lpIndex ); #define HvLpDma_Rc_InvalidAddress 4 #define HvLpDma_Rc_InvalidLength 5 -#endif // _HVLPEVENT_H +#endif /* _HVLPEVENT_H */ diff --git a/include/asm-ppc64/iSeries/HvReleaseData.h b/include/asm-ppc64/iSeries/HvReleaseData.h index 183e5e7..c0cd21c 100644 --- a/include/asm-ppc64/iSeries/HvReleaseData.h +++ b/include/asm-ppc64/iSeries/HvReleaseData.h @@ -1,17 +1,17 @@ /* * HvReleaseData.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,47 +19,43 @@ #ifndef _HVRELEASEDATA_H #define _HVRELEASEDATA_H -//============================================================================= -// -// This control block contains the critical information about the -// release so that it can be changed in the future (ie, the virtual -// address of the OS's NACA). -// +/* + * This control block contains the critical information about the + * release so that it can be changed in the future (ie, the virtual + * address of the OS's NACA). + */ #include #include -//============================================================================= -// -// When we IPL a secondary partition, we will check if if the -// secondary xMinPlicVrmIndex > the primary xVrmIndex. -// If it is then this tells PLIC that this secondary is not -// supported running on this "old" of a level of PLIC. -// -// Likewise, we will compare the primary xMinSlicVrmIndex to -// the secondary xVrmIndex. -// If the primary xMinSlicVrmDelta > secondary xVrmDelta then we -// know that this PLIC does not support running an OS "that old". -// -//============================================================================= +/* + * When we IPL a secondary partition, we will check if if the + * secondary xMinPlicVrmIndex > the primary xVrmIndex. + * If it is then this tells PLIC that this secondary is not + * supported running on this "old" of a level of PLIC. + * + * Likewise, we will compare the primary xMinSlicVrmIndex to + * the secondary xVrmIndex. + * If the primary xMinSlicVrmDelta > secondary xVrmDelta then we + * know that this PLIC does not support running an OS "that old". + */ -struct HvReleaseData -{ - u32 xDesc; // Descriptor "HvRD" ebcdic x00-x03 - u16 xSize; // Size of this control block x04-x05 - u16 xVpdAreasPtrOffset; // Offset in NACA of ItVpdAreas x06-x07 - struct naca_struct * xSlicNacaAddr; // Virt addr of SLIC NACA x08-x0F - u32 xMsNucDataOffset; // Offset of Linux Mapping Data x10-x13 - u32 xRsvd1; // Reserved x14-x17 - u16 xTagsMode:1; // 0 == tags active, 1 == tags inactive - u16 xAddressSize:1; // 0 == 64-bit, 1 == 32-bit - u16 xNoSharedProcs:1; // 0 == shared procs, 1 == no shared - u16 xNoHMT:1; // 0 == allow HMT, 1 == no HMT - u16 xRsvd2:12; // Reserved x18-x19 - u16 xVrmIndex; // VRM Index of OS image x1A-x1B - u16 xMinSupportedPlicVrmIndex;// Min PLIC level (soft) x1C-x1D - u16 xMinCompatablePlicVrmIndex;// Min PLIC levelP (hard) x1E-x1F - char xVrmName[12]; // Displayable name x20-x2B - char xRsvd3[20]; // Reserved x2C-x3F +struct HvReleaseData { + u32 xDesc; /* Descriptor "HvRD" ebcdic x00-x03 */ + u16 xSize; /* Size of this control block x04-x05 */ + u16 xVpdAreasPtrOffset; /* Offset in NACA of ItVpdAreas x06-x07 */ + struct naca_struct *xSlicNacaAddr; /* Virt addr of SLIC NACA x08-x0F */ + u32 xMsNucDataOffset; /* Offset of Linux Mapping Data x10-x13 */ + u32 xRsvd1; /* Reserved x14-x17 */ + u16 xTagsMode:1; /* 0 == tags active, 1 == tags inactive */ + u16 xAddressSize:1; /* 0 == 64-bit, 1 == 32-bit */ + u16 xNoSharedProcs:1; /* 0 == shared procs, 1 == no shared */ + u16 xNoHMT:1; /* 0 == allow HMT, 1 == no HMT */ + u16 xRsvd2:12; /* Reserved x18-x19 */ + u16 xVrmIndex; /* VRM Index of OS image x1A-x1B */ + u16 xMinSupportedPlicVrmIndex; /* Min PLIC level (soft) x1C-x1D */ + u16 xMinCompatablePlicVrmIndex; /* Min PLIC levelP (hard) x1E-x1F */ + char xVrmName[12]; /* Displayable name x20-x2B */ + char xRsvd3[20]; /* Reserved x2C-x3F */ }; #endif /* _HVRELEASEDATA_H */ diff --git a/include/asm-ppc64/iSeries/HvTypes.h b/include/asm-ppc64/iSeries/HvTypes.h index 3ec49c1..111191d 100644 --- a/include/asm-ppc64/iSeries/HvTypes.h +++ b/include/asm-ppc64/iSeries/HvTypes.h @@ -1,17 +1,17 @@ /* * HvTypes.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,74 +19,62 @@ #ifndef _HVTYPES_H #define _HVTYPES_H -//=========================================================================== -// Header File Id -// Name______________: HvTypes.H -// -// Description_______: -// -// General typedefs for the hypervisor. -// -// Declared Class(es): -// -//=========================================================================== +/* + * General typedefs for the hypervisor. + */ #include -//------------------------------------------------------------------- -// Typedefs -//------------------------------------------------------------------- typedef u8 HvLpIndex; typedef u16 HvLpInstanceId; -typedef u64 HvLpTOD; -typedef u64 HvLpSystemSerialNum; -typedef u8 HvLpDeviceSerialNum[12]; -typedef u16 HvLpSanHwSet; -typedef u16 HvLpBus; -typedef u16 HvLpBoard; -typedef u16 HvLpCard; -typedef u8 HvLpDeviceType[4]; -typedef u8 HvLpDeviceModel[3]; -typedef u64 HvIoToken; -typedef u8 HvLpName[8]; +typedef u64 HvLpTOD; +typedef u64 HvLpSystemSerialNum; +typedef u8 HvLpDeviceSerialNum[12]; +typedef u16 HvLpSanHwSet; +typedef u16 HvLpBus; +typedef u16 HvLpBoard; +typedef u16 HvLpCard; +typedef u8 HvLpDeviceType[4]; +typedef u8 HvLpDeviceModel[3]; +typedef u64 HvIoToken; +typedef u8 HvLpName[8]; typedef u32 HvIoId; typedef u64 HvRealMemoryIndex; -typedef u32 HvLpIndexMap; // Must hold HvMaxArchitectedLps bits!!! +typedef u32 HvLpIndexMap; /* Must hold HvMaxArchitectedLps bits!!! */ typedef u16 HvLpVrmIndex; typedef u32 HvXmGenerationId; -typedef u8 HvLpBusPool; -typedef u8 HvLpSharedPoolIndex; +typedef u8 HvLpBusPool; +typedef u8 HvLpSharedPoolIndex; typedef u16 HvLpSharedProcUnitsX100; typedef u8 HvLpVirtualLanIndex; -typedef u16 HvLpVirtualLanIndexMap; // Must hold HvMaxArchitectedVirtualLans bits!!! -typedef u16 HvBusNumber; // Hypervisor Bus Number -typedef u8 HvSubBusNumber; // Hypervisor SubBus Number -typedef u8 HvAgentId; // Hypervisor DevFn +typedef u16 HvLpVirtualLanIndexMap; /* Must hold HvMaxArchitectedVirtualLans bits!!! */ +typedef u16 HvBusNumber; /* Hypervisor Bus Number */ +typedef u8 HvSubBusNumber; /* Hypervisor SubBus Number */ +typedef u8 HvAgentId; /* Hypervisor DevFn */ + +#define HVMAXARCHITECTEDLPS 32 +#define HVMAXARCHITECTEDVIRTUALLANS 16 +#define HVMAXARCHITECTEDVIRTUALDISKS 32 +#define HVMAXARCHITECTEDVIRTUALCDROMS 8 +#define HVMAXARCHITECTEDVIRTUALTAPES 8 +#define HVCHUNKSIZE (256 * 1024) +#define HVPAGESIZE (4 * 1024) +#define HVLPMINMEGSPRIMARY 256 +#define HVLPMINMEGSSECONDARY 64 +#define HVCHUNKSPERMEG 4 +#define HVPAGESPERMEG 256 +#define HVPAGESPERCHUNK 64 -#define HVMAXARCHITECTEDLPS 32 -#define HVMAXARCHITECTEDVIRTUALLANS 16 -#define HVMAXARCHITECTEDVIRTUALDISKS 32 -#define HVMAXARCHITECTEDVIRTUALCDROMS 8 -#define HVMAXARCHITECTEDVIRTUALTAPES 8 -#define HVCHUNKSIZE 256 * 1024 -#define HVPAGESIZE 4 * 1024 -#define HVLPMINMEGSPRIMARY 256 -#define HVLPMINMEGSSECONDARY 64 -#define HVCHUNKSPERMEG 4 -#define HVPAGESPERMEG 256 -#define HVPAGESPERCHUNK 64 - -#define HvMaxArchitectedLps ((HvLpIndex)HVMAXARCHITECTEDLPS) +#define HvMaxArchitectedLps ((HvLpIndex)HVMAXARCHITECTEDLPS) #define HvMaxArchitectedVirtualLans ((HvLpVirtualLanIndex)16) #define HvLpIndexInvalid ((HvLpIndex)0xff) -//-------------------------------------------------------------------- -// Enums for the sub-components under PLIC -// Used in HvCall and HvPrimaryCall -//-------------------------------------------------------------------- -enum HvCallCompIds -{ +/* + * Enums for the sub-components under PLIC + * Used in HvCall and HvPrimaryCall + */ +enum HvCallCompIds { HvCallCompId = 0, HvCallCpuCtlsCompId = 1, HvCallCfgCompId = 2, @@ -97,18 +85,18 @@ enum HvCallCompIds HvCallSmCompId = 7, HvCallSpdCompId = 8, HvCallXmCompId = 9, - HvCallRioCompId = 10, + HvCallRioCompId = 10, HvCallRsvd3CompId = 11, HvCallRsvd2CompId = 12, HvCallRsvd1CompId = 13, HvCallMaxCompId = 14, - HvPrimaryCallCompId = 0, + HvPrimaryCallCompId = 0, HvPrimaryCallCfgCompId = 1, - HvPrimaryCallPciCompId = 2, + HvPrimaryCallPciCompId = 2, HvPrimaryCallSmCompId = 3, HvPrimaryCallSpdCompId = 4, HvPrimaryCallXmCompId = 5, - HvPrimaryCallRioCompId = 6, + HvPrimaryCallRioCompId = 6, HvPrimaryCallRsvd7CompId = 7, HvPrimaryCallRsvd6CompId = 8, HvPrimaryCallRsvd5CompId = 9, @@ -116,7 +104,7 @@ enum HvCallCompIds HvPrimaryCallRsvd3CompId = 11, HvPrimaryCallRsvd2CompId = 12, HvPrimaryCallRsvd1CompId = 13, - HvPrimaryCallMaxCompId = HvCallMaxCompId + HvPrimaryCallMaxCompId = HvCallMaxCompId }; struct HvLpBufferList { -- cgit v0.10.2 From fcee38952609fccb2bdfe166b3b96bd75a292aa6 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:34 -0700 Subject: [PATCH] ppc64 iSeries: more header file white space cleanups This patch just contains white space and comment cleanups in the iSeries headers files. There are no semantic changes. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-ppc64/iSeries/IoHriMainStore.h b/include/asm-ppc64/iSeries/IoHriMainStore.h index ff00e86..fbb3ee4 100644 --- a/include/asm-ppc64/iSeries/IoHriMainStore.h +++ b/include/asm-ppc64/iSeries/IoHriMainStore.h @@ -1,17 +1,17 @@ /* * IoHriMainStore.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -21,7 +21,7 @@ #define _IOHRIMAINSTORE_H /* Main Store Vpd for Condor,iStar,sStar */ -struct IoHriMainStoreSegment4 { +struct IoHriMainStoreSegment4 { u8 msArea0Exists:1; u8 msArea1Exists:1; u8 msArea2Exists:1; @@ -51,7 +51,7 @@ struct IoHriMainStoreSegment4 { u8 msArea1HasRiserVpd:1; u8 msArea2HasRiserVpd:1; u8 msArea3HasRiserVpd:1; - u8 reserved5:4; + u8 reserved5:4; u8 reserved6; u16 reserved7; @@ -82,8 +82,8 @@ struct IoHriMainStoreVpdFruData { }; struct IoHriMainStoreAdrRangeBlock { - void * blockStart __attribute((packed)); - void * blockEnd __attribute((packed)); + void *blockStart __attribute((packed)); + void *blockEnd __attribute((packed)); u32 blockProcChipId __attribute((packed)); }; @@ -102,7 +102,7 @@ struct IoHriMainStoreArea4 { u32 procNodeId __attribute((packed)); u32 numAdrRangeBlocks __attribute((packed)); - struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks] __attribute((packed)); + struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks] __attribute((packed)); struct IoHriMainStoreChipInfo1 chipInfo0 __attribute((packed)); struct IoHriMainStoreChipInfo1 chipInfo1 __attribute((packed)); @@ -113,17 +113,17 @@ struct IoHriMainStoreArea4 { struct IoHriMainStoreChipInfo1 chipInfo6 __attribute((packed)); struct IoHriMainStoreChipInfo1 chipInfo7 __attribute((packed)); - void * msRamAreaArray __attribute((packed)); + void *msRamAreaArray __attribute((packed)); u32 msRamAreaArrayNumEntries __attribute((packed)); u32 msRamAreaArrayEntrySize __attribute((packed)); u32 numaDimmExists __attribute((packed)); u32 numaDimmFunctional __attribute((packed)); - void * numaDimmArray __attribute((packed)); + void *numaDimmArray __attribute((packed)); u32 numaDimmArrayNumEntries __attribute((packed)); u32 numaDimmArrayEntrySize __attribute((packed)); - struct IoHriMainStoreVpdIdData idData __attribute((packed)); + struct IoHriMainStoreVpdIdData idData __attribute((packed)); u64 powerData __attribute((packed)); u64 cardAssemblyPartNum __attribute((packed)); @@ -143,7 +143,7 @@ struct IoHriMainStoreArea4 { }; -struct IoHriMainStoreSegment5 { +struct IoHriMainStoreSegment5 { u16 reserved1; u8 reserved2; u8 msVpdFormat; @@ -151,17 +151,14 @@ struct IoHriMainStoreSegment5 { u32 totalMainStore; u64 maxConfiguredMsAdr; - struct IoHriMainStoreArea4* msAreaArray; + struct IoHriMainStoreArea4 *msAreaArray; u32 msAreaArrayNumEntries; u32 msAreaArrayEntrySize; - u32 msAreaExists; + u32 msAreaExists; u32 msAreaFunctional; u64 reserved3; }; - - -#endif // _IOHRIMAINSTORE_H - +#endif /* _IOHRIMAINSTORE_H */ diff --git a/include/asm-ppc64/iSeries/IoHriProcessorVpd.h b/include/asm-ppc64/iSeries/IoHriProcessorVpd.h index 9654338..ccb7b7c 100644 --- a/include/asm-ppc64/iSeries/IoHriProcessorVpd.h +++ b/include/asm-ppc64/iSeries/IoHriProcessorVpd.h @@ -1,17 +1,17 @@ /* * IoHriProcessorVpd.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,16 +19,12 @@ #ifndef _IOHRIPROCESSORVPD_H #define _IOHRIPROCESSORVPD_H -//=================================================================== -// -// This struct maps Processor Vpd that is DMAd to SLIC by CSP -// - #include -struct IoHriProcessorVpd -{ - +/* + * This struct maps Processor Vpd that is DMAd to SLIC by CSP + */ +struct IoHriProcessorVpd { u8 xFormat; // VPD format indicator x00-x00 u8 xProcStatus:8; // Processor State x01-x01 u8 xSecondaryThreadCount; // Secondary thread cnt x02-x02 @@ -40,12 +36,12 @@ struct IoHriProcessorVpd u16 xRsvd2; // Reserved x06-x07 u32 xHwNodeId; // Hardware node id x08-x0B u32 xHwProcId; // Hardware processor id x0C-x0F - + u32 xTypeNum; // Card Type/CCIN number x10-x13 u32 xModelNum; // Model/Feature number x14-x17 u64 xSerialNum; // Serial number x18-x1F - char xPartNum[12]; // Book Part or FPU number x20-x2B - char xMfgID[4]; // Manufacturing ID x2C-x2F + char xPartNum[12]; // Book Part or FPU number x20-x2B + char xMfgID[4]; // Manufacturing ID x2C-x2F u32 xProcFreq; // Processor Frequency x30-x33 u32 xTimeBaseFreq; // Time Base Frequency x34-x37 @@ -71,7 +67,7 @@ struct IoHriProcessorVpd u32 xDataL3CacheSizeKB; // L3 data cache size in KB x80-x83 u32 xDataL3CacheLineSize; // L3 data cache block size x84-x87 u64 xRsvd6; // Reserved x88-x8F - + u64 xFruLabel; // Card Location Label x90-x97 u8 xSlotsOnCard; // Slots on card (0=no slots) x98-x98 u8 xPartLocFlag; // Location flag (0-pluggable 1-imbedded) x99-x99 @@ -79,10 +75,10 @@ struct IoHriProcessorVpd u8 xSmartCardPortNo; // Smart card port number x9C-x9C u8 xRsvd7; // Reserved x9D-x9D u16 xFrameIdAndRackUnit; // Frame ID and rack unit adr x9E-x9F - + u8 xRsvd8[24]; // Reserved xA0-xB7 - char xProcSrc[72]; // CSP format SRC xB8-xFF + char xProcSrc[72]; // CSP format SRC xB8-xFF }; #endif /* _IOHRIPROCESSORVPD_H */ diff --git a/include/asm-ppc64/iSeries/ItExtVpdPanel.h b/include/asm-ppc64/iSeries/ItExtVpdPanel.h index dee6b12..b714907 100644 --- a/include/asm-ppc64/iSeries/ItExtVpdPanel.h +++ b/include/asm-ppc64/iSeries/ItExtVpdPanel.h @@ -1,17 +1,17 @@ /* * ItExtVpdPanel.h * Copyright (C) 2002 Dave Boutcher IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -20,39 +20,31 @@ #define _ITEXTVPDPANEL_H /* - * - * This struct maps the panel information + * This struct maps the panel information * * Warning: * This data must match the architecture for the panel information - * */ - -/*------------------------------------------------------------------- - * Standard Includes - *------------------------------------------------------------------- -*/ #include -struct ItExtVpdPanel -{ - // Definition of the Extended Vpd On Panel Data Area - char systemSerial[8]; - char mfgID[4]; - char reserved1[24]; - char machineType[4]; - char systemID[6]; - char somUniqueCnt[4]; - char serialNumberCount; - char reserved2[7]; - u16 bbu3; - u16 bbu2; - u16 bbu1; - char xLocationLabel[8]; - u8 xRsvd1[6]; - u16 xFrameId; - u8 xRsvd2[48]; +struct ItExtVpdPanel { + /* Definition of the Extended Vpd On Panel Data Area */ + char systemSerial[8]; + char mfgID[4]; + char reserved1[24]; + char machineType[4]; + char systemID[6]; + char somUniqueCnt[4]; + char serialNumberCount; + char reserved2[7]; + u16 bbu3; + u16 bbu2; + u16 bbu1; + char xLocationLabel[8]; + u8 xRsvd1[6]; + u16 xFrameId; + u8 xRsvd2[48]; }; -#endif /* _ITEXTVPDPANEL_H */ +#endif /* _ITEXTVPDPANEL_H */ diff --git a/include/asm-ppc64/iSeries/ItIplParmsReal.h b/include/asm-ppc64/iSeries/ItIplParmsReal.h index 4d8b430..14f0b0a 100644 --- a/include/asm-ppc64/iSeries/ItIplParmsReal.h +++ b/include/asm-ppc64/iSeries/ItIplParmsReal.h @@ -1,17 +1,17 @@ /* * ItIplParmsReal.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,58 +19,51 @@ #ifndef _ITIPLPARMSREAL_H #define _ITIPLPARMSREAL_H -//============================================================================== -// -// This struct maps the IPL Parameters DMA'd from the SP. -// -// Warning: -// This data must map in exactly 64 bytes and match the architecture for -// the IPL parms -// -//============================================================================= - +/* + * This struct maps the IPL Parameters DMA'd from the SP. + * + * Warning: + * This data must map in exactly 64 bytes and match the architecture for + * the IPL parms + */ -//------------------------------------------------------------------- -// Standard Includes -//------------------------------------------------------------------- #include -struct ItIplParmsReal -{ - u8 xFormat; // Defines format of IplParms x00-x00 - u8 xRsvd01:6; // Reserved x01-x01 - u8 xAlternateSearch:1; // Alternate search indicator ... - u8 xUaSupplied:1; // UA Supplied on programmed IPL ... - u8 xLsUaFormat; // Format byte for UA x02-x02 - u8 xRsvd02; // Reserved x03-x03 - u32 xLsUa; // LS UA x04-x07 - u32 xUnusedLsLid; // First OS LID to load x08-x0B - u16 xLsBusNumber; // LS Bus Number x0C-x0D - u8 xLsCardAdr; // LS Card Address x0E-x0E - u8 xLsBoardAdr; // LS Board Address x0F-x0F - u32 xRsvd03; // Reserved x10-x13 - u8 xSpcnPresent:1; // SPCN present x14-x14 - u8 xCpmPresent:1; // CPM present ... - u8 xRsvd04:6; // Reserved ... - u8 xRsvd05:4; // Reserved x15-x15 - u8 xKeyLock:4; // Keylock setting ... - u8 xRsvd06:6; // Reserved x16-x16 - u8 xIplMode:2; // Ipl mode (A|B|C|D) ... - u8 xHwIplType; // Fast v slow v slow EC HW IPL x17-x17 - u16 xCpmEnabledIpl:1; // CPM in effect when IPL initiated x18-x19 - u16 xPowerOnResetIpl:1; // Indicate POR condition ... - u16 xMainStorePreserved:1; // Main Storage is preserved ... - u16 xRsvd07:13; // Reserved ... - u16 xIplSource:16; // Ipl source x1A-x1B - u8 xIplReason:8; // Reason for this IPL x1C-x1C - u8 xRsvd08; // Reserved x1D-x1D - u16 xRsvd09; // Reserved x1E-x1F - u16 xSysBoxType; // System Box Type x20-x21 - u16 xSysProcType; // System Processor Type x22-x23 - u32 xRsvd10; // Reserved x24-x27 - u64 xRsvd11; // Reserved x28-x2F - u64 xRsvd12; // Reserved x30-x37 - u64 xRsvd13; // Reserved x38-x3F +struct ItIplParmsReal { + u8 xFormat; // Defines format of IplParms x00-x00 + u8 xRsvd01:6; // Reserved x01-x01 + u8 xAlternateSearch:1; // Alternate search indicator ... + u8 xUaSupplied:1; // UA Supplied on programmed IPL... + u8 xLsUaFormat; // Format byte for UA x02-x02 + u8 xRsvd02; // Reserved x03-x03 + u32 xLsUa; // LS UA x04-x07 + u32 xUnusedLsLid; // First OS LID to load x08-x0B + u16 xLsBusNumber; // LS Bus Number x0C-x0D + u8 xLsCardAdr; // LS Card Address x0E-x0E + u8 xLsBoardAdr; // LS Board Address x0F-x0F + u32 xRsvd03; // Reserved x10-x13 + u8 xSpcnPresent:1; // SPCN present x14-x14 + u8 xCpmPresent:1; // CPM present ... + u8 xRsvd04:6; // Reserved ... + u8 xRsvd05:4; // Reserved x15-x15 + u8 xKeyLock:4; // Keylock setting ... + u8 xRsvd06:6; // Reserved x16-x16 + u8 xIplMode:2; // Ipl mode (A|B|C|D) ... + u8 xHwIplType; // Fast v slow v slow EC HW IPL x17-x17 + u16 xCpmEnabledIpl:1; // CPM in effect when IPL initiatedx18-x19 + u16 xPowerOnResetIpl:1; // Indicate POR condition ... + u16 xMainStorePreserved:1; // Main Storage is preserved ... + u16 xRsvd07:13; // Reserved ... + u16 xIplSource:16; // Ipl source x1A-x1B + u8 xIplReason:8; // Reason for this IPL x1C-x1C + u8 xRsvd08; // Reserved x1D-x1D + u16 xRsvd09; // Reserved x1E-x1F + u16 xSysBoxType; // System Box Type x20-x21 + u16 xSysProcType; // System Processor Type x22-x23 + u32 xRsvd10; // Reserved x24-x27 + u64 xRsvd11; // Reserved x28-x2F + u64 xRsvd12; // Reserved x30-x37 + u64 xRsvd13; // Reserved x38-x3F }; #endif /* _ITIPLPARMSREAL_H */ diff --git a/include/asm-ppc64/iSeries/ItLpNaca.h b/include/asm-ppc64/iSeries/ItLpNaca.h index 5baffdd..942b07d 100644 --- a/include/asm-ppc64/iSeries/ItLpNaca.h +++ b/include/asm-ppc64/iSeries/ItLpNaca.h @@ -1,17 +1,17 @@ /* * ItLpNaca.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,18 +19,13 @@ #ifndef _ITLPNACA_H #define _ITLPNACA_H -//============================================================================= -// -// This control block contains the data that is shared between the -// hypervisor (PLIC) and the OS. -// -//============================================================================= +/* + * This control block contains the data that is shared between the + * hypervisor (PLIC) and the OS. + */ -struct ItLpNaca -{ -//============================================================================= +struct ItLpNaca { // CACHE_LINE_1 0x0000 - 0x007F Contains read-only data -//============================================================================= u32 xDesc; // Eye catcher x00-x03 u16 xSize; // Size of this class x04-x05 u16 xIntHdlrOffset; // Offset to IntHdlr array x06-x07 @@ -59,30 +54,23 @@ struct ItLpNaca u64 xLoadAreaAddr; // ER address of load area x28-x2F u32 xLoadAreaChunks; // Chunks for the load area x30-x33 u32 xPaseSysCallCRMask; // Mask used to test CR before x34-x37 - // doing an ASR switch on PASE - // system call. - u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f - u8 xRsvd1_4[64]; // x40-x7F - -//============================================================================= + // doing an ASR switch on PASE + // system call. + u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f + u8 xRsvd1_4[64]; // x40-x7F + // CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data -//============================================================================= u8 xRsvd2_0[128]; // Reserved x00-x7F -//============================================================================= // CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators -// NB: Padding required to keep xInterrruptHdlr at x300 which is required +// NB: Padding required to keep xInterrruptHdlr at x300 which is required // for v4r4 PLIC. -//============================================================================= u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F u8 xRsvd3_0[384]; // Reserved 180-2FF -//============================================================================= + // CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt // handlers -//============================================================================= u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF }; -//============================================================================= - #endif /* _ITLPNACA_H */ diff --git a/include/asm-ppc64/iSeries/ItLpQueue.h b/include/asm-ppc64/iSeries/ItLpQueue.h index 4f4dde2..b2bdef4 100644 --- a/include/asm-ppc64/iSeries/ItLpQueue.h +++ b/include/asm-ppc64/iSeries/ItLpQueue.h @@ -1,17 +1,17 @@ /* * ItLpQueue.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,47 +19,47 @@ #ifndef _ITLPQUEUE_H #define _ITLPQUEUE_H -//============================================================================= -// -// This control block defines the simple LP queue structure that is -// shared between the hypervisor (PLIC) and the OS in order to send -// events to an LP. -// +/* + * This control block defines the simple LP queue structure that is + * shared between the hypervisor (PLIC) and the OS in order to send + * events to an LP. + */ #include #include struct HvLpEvent; -#define ITMaxLpQueues 8 +#define ITMaxLpQueues 8 #define NotUsed 0 // Queue will not be used by PLIC #define DedicatedIo 1 // Queue dedicated to IO processor specified #define DedicatedLp 2 // Queue dedicated to LP specified #define Shared 3 // Queue shared for both IO and LP -#define LpEventStackSize 4096 -#define LpEventMaxSize 256 -#define LpEventAlign 64 +#define LpEventStackSize 4096 +#define LpEventMaxSize 256 +#define LpEventAlign 64 -struct ItLpQueue -{ -// -// The xSlicCurEventPtr is the pointer to the next event stack entry that will -// become valid. The OS must peek at this entry to determine if it is valid. -// PLIC will set the valid indicator as the very last store into that entry. -// -// When the OS has completed processing of the event then it will mark the event -// as invalid so that PLIC knows it can store into that event location again. -// -// If the event stack fills and there are overflow events, then PLIC will set -// the xPlicOverflowIntPending flag in which case the OS will have to fetch the -// additional LP events once they have drained the event stack. -// -// The first 16-bytes are known by both the OS and PLIC. The remainder of the -// cache line is for use by the OS. -// -//============================================================================= +struct ItLpQueue { +/* + * The xSlicCurEventPtr is the pointer to the next event stack entry + * that will become valid. The OS must peek at this entry to determine + * if it is valid. PLIC will set the valid indicator as the very last + * store into that entry. + * + * When the OS has completed processing of the event then it will mark + * the event as invalid so that PLIC knows it can store into that event + * location again. + * + * If the event stack fills and there are overflow events, then PLIC + * will set the xPlicOverflowIntPending flag in which case the OS will + * have to fetch the additional LP events once they have drained the + * event stack. + * + * The first 16-bytes are known by both the OS and PLIC. The remainder + * of the cache line is for use by the OS. + */ u8 xPlicOverflowIntPending;// 0x00 Overflow events are pending u8 xPlicStatus; // 0x01 DedicatedIo or DedicatedLp or NotUsed u16 xSlicLogicalProcIndex; // 0x02 Logical Proc Index for correlation @@ -76,17 +76,17 @@ struct ItLpQueue extern struct ItLpQueue xItLpQueue; -extern struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * ); -extern int ItLpQueue_isLpIntPending( struct ItLpQueue * ); -extern unsigned ItLpQueue_process( struct ItLpQueue *, struct pt_regs * ); -extern void ItLpQueue_clearValid( struct HvLpEvent * ); +extern struct HvLpEvent * ItLpQueue_getNextLpEvent(struct ItLpQueue *); +extern int ItLpQueue_isLpIntPending(struct ItLpQueue *); +extern unsigned ItLpQueue_process(struct ItLpQueue *, struct pt_regs *); +extern void ItLpQueue_clearValid(struct HvLpEvent *); -static __inline__ void process_iSeries_events( void ) +static __inline__ void process_iSeries_events(void) { __asm__ __volatile__ ( " li 0,0x5555 \n\ sc" - : : : "r0", "r3" ); + : : : "r0", "r3"); } #endif /* _ITLPQUEUE_H */ diff --git a/include/asm-ppc64/iSeries/ItLpRegSave.h b/include/asm-ppc64/iSeries/ItLpRegSave.h index dafc4c8..1b3087e 100644 --- a/include/asm-ppc64/iSeries/ItLpRegSave.h +++ b/include/asm-ppc64/iSeries/ItLpRegSave.h @@ -1,17 +1,17 @@ /* * ItLpRegSave.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,33 +19,30 @@ #ifndef _ITLPREGSAVE_H #define _ITLPREGSAVE_H -//===================================================================================== -// -// This control block contains the data that is shared between PLIC -// and the OS -// -// +/* + * This control block contains the data that is shared between PLIC + * and the OS + */ -struct ItLpRegSave -{ +struct ItLpRegSave { u32 xDesc; // Eye catcher "LpRS" ebcdic 000-003 u16 xSize; // Size of this class 004-005 u8 xInUse; // Area is live 006-007 - u8 xRsvd1[9]; // Reserved 007-00F + u8 xRsvd1[9]; // Reserved 007-00F - u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F + u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F u32 xCTRL; // Control Register 170-173 - u32 xDEC; // Decrementer 174-177 + u32 xDEC; // Decrementer 174-177 u32 xFPSCR; // FP Status and Control Reg 178-17B u32 xPVR; // Processor Version Number 17C-17F - + u64 xMMCR0; // Monitor Mode Control Reg 0 180-187 u32 xPMC1; // Perf Monitor Counter 1 188-18B u32 xPMC2; // Perf Monitor Counter 2 18C-18F u32 xPMC3; // Perf Monitor Counter 3 190-193 u32 xPMC4; // Perf Monitor Counter 4 194-197 u32 xPIR; // Processor ID Reg 198-19B - + u32 xMMCR1; // Monitor Mode Control Reg 1 19C-19F u32 xMMCRA; // Monitor Mode Control Reg A 1A0-1A3 u32 xPMC5; // Perf Monitor Counter 5 1A4-1A7 @@ -57,17 +54,17 @@ struct ItLpRegSave u32 xRsvd; // Reserved 1BC-1BF u64 xACCR; // Address Compare Control Reg 1C0-1C7 - u64 xIMR; // Instruction Match Register 1C8-1CF - u64 xSDR1; // Storage Description Reg 1 1D0-1D7 + u64 xIMR; // Instruction Match Register 1C8-1CF + u64 xSDR1; // Storage Description Reg 1 1D0-1D7 u64 xSPRG0; // Special Purpose Reg General0 1D8-1DF u64 xSPRG1; // Special Purpose Reg General1 1E0-1E7 u64 xSPRG2; // Special Purpose Reg General2 1E8-1EF u64 xSPRG3; // Special Purpose Reg General3 1F0-1F7 u64 xTB; // Time Base Register 1F8-1FF - + u64 xFPR[32]; // Floating Point Registers 200-2FF - u64 xMSR; // Machine State Register 300-307 + u64 xMSR; // Machine State Register 300-307 u64 xNIA; // Next Instruction Address 308-30F u64 xDABR; // Data Address Breakpoint Reg 310-317 @@ -76,8 +73,8 @@ struct ItLpRegSave u64 xHID0; // HW Implementation Dependent0 320-327 u64 xHID4; // HW Implementation Dependent4 328-32F - u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337 - u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F + u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337 + u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F u64 xSDAR; // Sample Data Address Register 340-347 u64 xSIAR; // Sample Inst Address Register 348-34F diff --git a/include/asm-ppc64/iSeries/ItSpCommArea.h b/include/asm-ppc64/iSeries/ItSpCommArea.h index f1b56f9..5535f82 100644 --- a/include/asm-ppc64/iSeries/ItSpCommArea.h +++ b/include/asm-ppc64/iSeries/ItSpCommArea.h @@ -1,29 +1,27 @@ /* * ItSpCommArea.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #ifndef _ITSPCOMMAREA_H #define _ITSPCOMMAREA_H -struct SpCommArea -{ +struct SpCommArea { u32 xDesc; // Descriptor (only in new formats) 000-003 u8 xFormat; // Format (only in new formats) 004-004 u8 xRsvd1[11]; // Reserved 005-00F diff --git a/include/asm-ppc64/iSeries/ItVpdAreas.h b/include/asm-ppc64/iSeries/ItVpdAreas.h index d120439..cfb9925 100644 --- a/include/asm-ppc64/iSeries/ItVpdAreas.h +++ b/include/asm-ppc64/iSeries/ItVpdAreas.h @@ -1,17 +1,17 @@ /* * ItVpdAreas.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -19,78 +19,75 @@ #ifndef _ITVPDAREAS_H #define _ITVPDAREAS_H -//===================================================================================== -// -// This file defines the address and length of all of the VPD area passed to -// the OS from PLIC (most of which start from the SP). -// +/* + * This file defines the address and length of all of the VPD area passed to + * the OS from PLIC (most of which start from the SP). + */ #include -// VPD Entry index is carved in stone - cannot be changed (easily). -#define ItVpdCecVpd 0 -#define ItVpdDynamicSpace 1 -#define ItVpdExtVpd 2 -#define ItVpdExtVpdOnPanel 3 -#define ItVpdFirstPaca 4 -#define ItVpdIoVpd 5 -#define ItVpdIplParms 6 -#define ItVpdMsVpd 7 -#define ItVpdPanelVpd 8 -#define ItVpdLpNaca 9 -#define ItVpdBackplaneAndMaybeClockCardVpd 10 -#define ItVpdRecoveryLogBuffer 11 -#define ItVpdSpCommArea 12 -#define ItVpdSpLogBuffer 13 -#define ItVpdSpLogBufferSave 14 -#define ItVpdSpCardVpd 15 -#define ItVpdFirstProcVpd 16 -#define ItVpdApModelVpd 17 -#define ItVpdClockCardVpd 18 -#define ItVpdBusExtCardVpd 19 -#define ItVpdProcCapacityVpd 20 -#define ItVpdInteractiveCapacityVpd 21 -#define ItVpdFirstSlotLabel 22 -#define ItVpdFirstLpQueue 23 -#define ItVpdFirstL3CacheVpd 24 -#define ItVpdFirstProcFruVpd 25 - -#define ItVpdMaxEntries 26 +/* VPD Entry index is carved in stone - cannot be changed (easily). */ +#define ItVpdCecVpd 0 +#define ItVpdDynamicSpace 1 +#define ItVpdExtVpd 2 +#define ItVpdExtVpdOnPanel 3 +#define ItVpdFirstPaca 4 +#define ItVpdIoVpd 5 +#define ItVpdIplParms 6 +#define ItVpdMsVpd 7 +#define ItVpdPanelVpd 8 +#define ItVpdLpNaca 9 +#define ItVpdBackplaneAndMaybeClockCardVpd 10 +#define ItVpdRecoveryLogBuffer 11 +#define ItVpdSpCommArea 12 +#define ItVpdSpLogBuffer 13 +#define ItVpdSpLogBufferSave 14 +#define ItVpdSpCardVpd 15 +#define ItVpdFirstProcVpd 16 +#define ItVpdApModelVpd 17 +#define ItVpdClockCardVpd 18 +#define ItVpdBusExtCardVpd 19 +#define ItVpdProcCapacityVpd 20 +#define ItVpdInteractiveCapacityVpd 21 +#define ItVpdFirstSlotLabel 22 +#define ItVpdFirstLpQueue 23 +#define ItVpdFirstL3CacheVpd 24 +#define ItVpdFirstProcFruVpd 25 +#define ItVpdMaxEntries 26 -#define ItDmaMaxEntries 10 +#define ItDmaMaxEntries 10 -#define ItVpdAreasMaxSlotLabels 192 +#define ItVpdAreasMaxSlotLabels 192 struct SlicVpdAdrs { u32 pad1; - void * vpdAddr; + void *vpdAddr; }; -struct ItVpdAreas -{ - u32 xSlicDesc; // Descriptor 000-003 - u16 xSlicSize; // Size of this control block 004-005 - u16 xPlicAdjustVpdLens:1; // Flag to indicate new interface 006-007 - u16 xRsvd1:15; // Reserved bits ... - u16 xSlicVpdEntries; // Number of VPD entries 008-009 - u16 xSlicDmaEntries; // Number of DMA entries 00A-00B - u16 xSlicMaxLogicalProcs; // Maximum logical processors 00C-00D - u16 xSlicMaxPhysicalProcs; // Maximum physical processors 00E-00F - u16 xSlicDmaToksOffset; // Offset into this of array 010-011 - u16 xSlicVpdAdrsOffset; // Offset into this of array 012-013 - u16 xSlicDmaLensOffset; // Offset into this of array 014-015 - u16 xSlicVpdLensOffset; // Offset into this of array 016-017 - u16 xSlicMaxSlotLabels; // Maximum number of slot labels 018-019 - u16 xSlicMaxLpQueues; // Maximum number of LP Queues 01A-01B - u8 xRsvd2[4]; // Reserved 01C-01F - u64 xRsvd3[12]; // Reserved 020-07F - u32 xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths 080-0A7 - u32 xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens 0A8-0CF - u32 xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths 0D0-12F - void * xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF +struct ItVpdAreas { + u32 xSlicDesc; // Descriptor 000-003 + u16 xSlicSize; // Size of this control block 004-005 + u16 xPlicAdjustVpdLens:1; // Flag to indicate new interface006-007 + u16 xRsvd1:15; // Reserved bits ... + u16 xSlicVpdEntries; // Number of VPD entries 008-009 + u16 xSlicDmaEntries; // Number of DMA entries 00A-00B + u16 xSlicMaxLogicalProcs; // Maximum logical processors 00C-00D + u16 xSlicMaxPhysicalProcs; // Maximum physical processors 00E-00F + u16 xSlicDmaToksOffset; // Offset into this of array 010-011 + u16 xSlicVpdAdrsOffset; // Offset into this of array 012-013 + u16 xSlicDmaLensOffset; // Offset into this of array 014-015 + u16 xSlicVpdLensOffset; // Offset into this of array 016-017 + u16 xSlicMaxSlotLabels; // Maximum number of slot labels018-019 + u16 xSlicMaxLpQueues; // Maximum number of LP Queues 01A-01B + u8 xRsvd2[4]; // Reserved 01C-01F + u64 xRsvd3[12]; // Reserved 020-07F + u32 xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths 080-0A7 + u32 xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens 0A8-0CF + u32 xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths 0D0-12F + void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF }; #endif /* _ITVPDAREAS_H */ diff --git a/include/asm-ppc64/iSeries/LparData.h b/include/asm-ppc64/iSeries/LparData.h index e54f3b6..a9fd6e2 100644 --- a/include/asm-ppc64/iSeries/LparData.h +++ b/include/asm-ppc64/iSeries/LparData.h @@ -1,17 +1,17 @@ /* * LparData.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -34,16 +34,15 @@ #include #include -extern struct LparMap xLparMap; -extern struct HvReleaseData hvReleaseData; -extern struct ItLpNaca itLpNaca; -extern struct ItIplParmsReal xItIplParmsReal; -extern struct ItExtVpdPanel xItExtVpdPanel; -extern struct IoHriProcessorVpd xIoHriProcessorVpd[]; -extern struct ItLpQueue xItLpQueue; -extern struct ItVpdAreas itVpdAreas; -extern u64 xMsVpd[]; -extern struct msChunks msChunks; - +extern struct LparMap xLparMap; +extern struct HvReleaseData hvReleaseData; +extern struct ItLpNaca itLpNaca; +extern struct ItIplParmsReal xItIplParmsReal; +extern struct ItExtVpdPanel xItExtVpdPanel; +extern struct IoHriProcessorVpd xIoHriProcessorVpd[]; +extern struct ItLpQueue xItLpQueue; +extern struct ItVpdAreas itVpdAreas; +extern u64 xMsVpd[]; +extern struct msChunks msChunks; #endif /* _LPARDATA_H */ diff --git a/include/asm-ppc64/iSeries/LparMap.h b/include/asm-ppc64/iSeries/LparMap.h index 075205b..1505c4f 100644 --- a/include/asm-ppc64/iSeries/LparMap.h +++ b/include/asm-ppc64/iSeries/LparMap.h @@ -1,17 +1,17 @@ /* * LparMap.h * Copyright (C) 2001 Mike Corrigan IBM Corporation - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -21,13 +21,14 @@ #include -/* The iSeries hypervisor will set up mapping for one or more +/* + * The iSeries hypervisor will set up mapping for one or more * ESID/VSID pairs (in SLB/segment registers) and will set up * mappings of one or more ranges of pages to VAs. * We will have the hypervisor set up the ESID->VSID mapping * for the four kernel segments (C-F). With shared processors, * the hypervisor will clear all segment registers and reload - * these four whenever the processor is switched from one + * these four whenever the processor is switched from one * partition to another. */ @@ -38,30 +39,29 @@ * need to be located within the load area (if the total partition size * is 64 MB), but cannot be mapped. Typically, this should specify * to map half (32 MB) of the load area. - * - * The hypervisor will set up page table entries for the number of + * + * The hypervisor will set up page table entries for the number of * pages specified. * * In 32-bit mode, the hypervisor will load all four of the - * segment registers (identified by the low-order four bits of the + * segment registers (identified by the low-order four bits of the * Esid field. In 64-bit mode, the hypervisor will load one SLB * entry to map the Esid to the Vsid. */ -// Hypervisor initially maps 32MB of the load area -#define HvPagesToMap 8192 +/* Hypervisor initially maps 32MB of the load area */ +#define HvPagesToMap 8192 -struct LparMap -{ - u64 xNumberEsids; // Number of ESID/VSID pairs (1) - u64 xNumberRanges; // Number of VA ranges to map (1) - u64 xSegmentTableOffs; // Page number within load area of seg table (0) - u64 xRsvd[5]; // Reserved (0) - u64 xKernelEsid; // Esid used to map kernel load (0x0C00000000) - u64 xKernelVsid; // Vsid used to map kernel load (0x0C00000000) - u64 xPages; // Number of pages to be mapped (8192) - u64 xOffset; // Offset from start of load area (0) - u64 xVPN; // Virtual Page Number (0x000C000000000000) +struct LparMap { + u64 xNumberEsids; // Number of ESID/VSID pairs (1) + u64 xNumberRanges; // Number of VA ranges to map (1) + u64 xSegmentTableOffs; // Page number within load area of seg table (0) + u64 xRsvd[5]; + u64 xKernelEsid; // Esid used to map kernel load (0x0C00000000) + u64 xKernelVsid; // Vsid used to map kernel load (0x0C00000000) + u64 xPages; // Number of pages to be mapped (8192) + u64 xOffset; // Offset from start of load area (0) + u64 xVPN; // Virtual Page Number (0x000C000000000000) }; #endif /* _LPARMAP_H */ diff --git a/include/asm-ppc64/iSeries/XmPciLpEvent.h b/include/asm-ppc64/iSeries/XmPciLpEvent.h index a3d27f1..9c80079 100644 --- a/include/asm-ppc64/iSeries/XmPciLpEvent.h +++ b/include/asm-ppc64/iSeries/XmPciLpEvent.h @@ -1,8 +1,6 @@ - #ifndef __XMPCILPEVENT_H__ #define __XMPCILPEVENT_H__ - #ifdef __cplusplus extern "C" { #endif @@ -10,7 +8,6 @@ extern "C" { int XmPciLpEvent_init(void); void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); - #ifdef __cplusplus } #endif diff --git a/include/asm-ppc64/iSeries/iSeries_io.h b/include/asm-ppc64/iSeries/iSeries_io.h index f52b759..9f79413 100644 --- a/include/asm-ppc64/iSeries/iSeries_io.h +++ b/include/asm-ppc64/iSeries/iSeries_io.h @@ -5,32 +5,33 @@ #ifdef CONFIG_PPC_ISERIES #include -/************************************************************************/ -/* File iSeries_io.h created by Allan Trautman on Thu Dec 28 2000. */ -/************************************************************************/ -/* Remaps the io.h for the iSeries Io */ -/* Copyright (C) 20yy Allan H Trautman, IBM Corporation */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that 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., */ -/* 59 Temple Place, Suite 330, */ -/* Boston, MA 02111-1307 USA */ -/************************************************************************/ -/* Change Activity: */ -/* Created December 28, 2000 */ -/* End Change Activity */ -/************************************************************************/ +/* + * File iSeries_io.h created by Allan Trautman on Thu Dec 28 2000. + * + * Remaps the io.h for the iSeries Io + * Copyright (C) 2000 Allan H Trautman, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * Change Activity: + * Created December 28, 2000 + * End Change Activity + */ + extern u8 iSeries_Read_Byte(const volatile void __iomem * IoAddress); extern u16 iSeries_Read_Word(const volatile void __iomem * IoAddress); extern u32 iSeries_Read_Long(const volatile void __iomem * IoAddress); @@ -39,8 +40,10 @@ extern void iSeries_Write_Word(u16 IoData, volatile void __iomem * IoAddress); extern void iSeries_Write_Long(u32 IoData, volatile void __iomem * IoAddress); extern void iSeries_memset_io(volatile void __iomem *dest, char x, size_t n); -extern void iSeries_memcpy_toio(volatile void __iomem *dest, void *source, size_t n); -extern void iSeries_memcpy_fromio(void *dest, const volatile void __iomem *source, size_t n); +extern void iSeries_memcpy_toio(volatile void __iomem *dest, void *source, + size_t n); +extern void iSeries_memcpy_fromio(void *dest, + const volatile void __iomem *source, size_t n); #endif /* CONFIG_PPC_ISERIES */ #endif /* _ISERIES_IO_H */ diff --git a/include/asm-ppc64/iSeries/iSeries_pci.h b/include/asm-ppc64/iSeries/iSeries_pci.h index 5769cff..9c6d645 100644 --- a/include/asm-ppc64/iSeries/iSeries_pci.h +++ b/include/asm-ppc64/iSeries/iSeries_pci.h @@ -1,112 +1,113 @@ #ifndef _ISERIES_64_PCI_H #define _ISERIES_64_PCI_H -/************************************************************************/ -/* File iSeries_pci.h created by Allan Trautman on Tue Feb 20, 2001. */ -/************************************************************************/ -/* Define some useful macros for the iSeries pci routines. */ -/* Copyright (C) 2001 Allan H Trautman, IBM Corporation */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that 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., */ -/* 59 Temple Place, Suite 330, */ -/* Boston, MA 02111-1307 USA */ -/************************************************************************/ -/* Change Activity: */ -/* Created Feb 20, 2001 */ -/* Added device reset, March 22, 2001 */ -/* Ported to ppc64, May 25, 2001 */ -/* End Change Activity */ -/************************************************************************/ +/* + * File iSeries_pci.h created by Allan Trautman on Tue Feb 20, 2001. + * + * Define some useful macros for the iSeries pci routines. + * Copyright (C) 2001 Allan H Trautman, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * Change Activity: + * Created Feb 20, 2001 + * Added device reset, March 22, 2001 + * Ported to ppc64, May 25, 2001 + * End Change Activity + */ #include #include -struct pci_dev; /* For Forward Reference */ +struct pci_dev; /* For Forward Reference */ struct iSeries_Device_Node; -/************************************************************************/ -/* Gets iSeries Bus, SubBus, DevFn using iSeries_Device_Node structure */ -/************************************************************************/ +/* + * Gets iSeries Bus, SubBus, DevFn using iSeries_Device_Node structure + */ #define ISERIES_BUS(DevPtr) DevPtr->DsaAddr.Dsa.busNumber #define ISERIES_SUBBUS(DevPtr) DevPtr->DsaAddr.Dsa.subBusNumber #define ISERIES_DEVICE(DevPtr) DevPtr->DsaAddr.Dsa.deviceId #define ISERIES_DSA(DevPtr) DevPtr->DsaAddr.DsaAddr #define ISERIES_DEVFUN(DevPtr) DevPtr->DevFn -#define ISERIES_DEVNODE(PciDev) ((struct iSeries_Device_Node*)PciDev->sysdata) +#define ISERIES_DEVNODE(PciDev) ((struct iSeries_Device_Node*)PciDev->sysdata) #define EADsMaxAgents 7 -/************************************************************************/ -/* Decodes Linux DevFn to iSeries DevFn, bridge device, or function. */ -/* For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h */ -/************************************************************************/ +/* + * Decodes Linux DevFn to iSeries DevFn, bridge device, or function. + * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h + */ -#define ISERIES_PCI_AGENTID(idsel,func) ((idsel & 0x0F) << 4) | (func & 0x07) -#define ISERIES_ENCODE_DEVICE(agentid) ((0x10) | ((agentid&0x20)>>2) | (agentid&07)) +#define ISERIES_PCI_AGENTID(idsel, func) \ + ((idsel & 0x0F) << 4) | (func & 0x07) +#define ISERIES_ENCODE_DEVICE(agentid) \ + ((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07)) -#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) -#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) +#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) +#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) /* * N.B. the ISERIES_DECODE_* macros are not used anywhere, and I think * the 0x71 (at least) must be wrong - 0x78 maybe? -- paulus. */ -#define ISERIES_DECODE_DEVFN(linuxdevfn) (((linuxdevfn & 0x71) << 1) | (linuxdevfn & 0x07)) -#define ISERIES_DECODE_DEVICE(linuxdevfn) (((linuxdevfn & 0x38) >> 3) |(((linuxdevfn & 0x40) >> 2) + 0x10)) -#define ISERIES_DECODE_FUNCTION(linuxdevfn) (linuxdevfn & 0x07) - -/************************************************************************/ -/* Converts Virtual Address to Real Address for Hypervisor calls */ -/************************************************************************/ +#define ISERIES_DECODE_DEVFN(linuxdevfn) \ + (((linuxdevfn & 0x71) << 1) | (linuxdevfn & 0x07)) +#define ISERIES_DECODE_DEVICE(linuxdevfn) \ + (((linuxdevfn & 0x38) >> 3) | (((linuxdevfn & 0x40) >> 2) + 0x10)) +#define ISERIES_DECODE_FUNCTION(linuxdevfn) \ + (linuxdevfn & 0x07) -#define ISERIES_HV_ADDR(virtaddr) (0x8000000000000000 | virt_to_abs(virtaddr)) - -/************************************************************************/ -/* iSeries Device Information */ -/************************************************************************/ +/* + * Converts Virtual Address to Real Address for Hypervisor calls + */ +#define ISERIES_HV_ADDR(virtaddr) \ + (0x8000000000000000 | virt_to_abs(virtaddr)) +/* + * iSeries Device Information + */ struct iSeries_Device_Node { struct list_head Device_List; - struct pci_dev* PciDev; /* Pointer to pci_dev structure*/ - union HvDsaMap DsaAddr; /* Direct Select Address */ - /* busNumber,subBusNumber, */ - /* deviceId, barNumber */ - HvAgentId AgentId; /* Hypervisor DevFn */ - int DevFn; /* Linux devfn */ - int BarOffset; - int Irq; /* Assigned IRQ */ - int ReturnCode; /* Return Code Holder */ - int IoRetry; /* Current Retry Count */ - int Flags; /* Possible flags(disable/bist)*/ - u16 Vendor; /* Vendor ID */ - u8 LogicalSlot; /* Hv Slot Index for Tces */ - struct iommu_table* iommu_table;/* Device TCE Table */ - u8 PhbId; /* Phb Card is on. */ - u16 Board; /* Board Number */ - u8 FrameId; /* iSeries spcn Frame Id */ - char CardLocation[4];/* Char format of planar vpd */ - char Location[20]; /* Frame 1, Card C10 */ + struct pci_dev *PciDev; + union HvDsaMap DsaAddr; /* Direct Select Address */ + /* busNumber, subBusNumber, */ + /* deviceId, barNumber */ + HvAgentId AgentId; /* Hypervisor DevFn */ + int DevFn; /* Linux devfn */ + int BarOffset; + int Irq; /* Assigned IRQ */ + int ReturnCode; /* Return Code Holder */ + int IoRetry; /* Current Retry Count */ + int Flags; /* Possible flags(disable/bist)*/ + u16 Vendor; /* Vendor ID */ + u8 LogicalSlot; /* Hv Slot Index for Tces */ + struct iommu_table *iommu_table;/* Device TCE Table */ + u8 PhbId; /* Phb Card is on. */ + u16 Board; /* Board Number */ + u8 FrameId; /* iSeries spcn Frame Id */ + char CardLocation[4];/* Char format of planar vpd */ + char Location[20]; /* Frame 1, Card C10 */ }; -/************************************************************************/ -/* Functions */ -/************************************************************************/ - -extern int iSeries_Device_Information(struct pci_dev*,char*, int); -extern void iSeries_Get_Location_Code(struct iSeries_Device_Node*); -extern int iSeries_Device_ToggleReset(struct pci_dev* PciDev, int AssertTime, int DelayTime); +extern int iSeries_Device_Information(struct pci_dev*, char*, int); +extern void iSeries_Get_Location_Code(struct iSeries_Device_Node*); +extern int iSeries_Device_ToggleReset(struct pci_dev* PciDev, + int AssertTime, int DelayTime); #endif /* _ISERIES_64_PCI_H */ diff --git a/include/asm-ppc64/iSeries/mf.h b/include/asm-ppc64/iSeries/mf.h index db333e1..7e6a0d9 100644 --- a/include/asm-ppc64/iSeries/mf.h +++ b/include/asm-ppc64/iSeries/mf.h @@ -9,17 +9,16 @@ * all partitions in the iSeries. It also provides miscellaneous low-level * machine facility type operations. * - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA diff --git a/include/asm-ppc64/iSeries/vio.h b/include/asm-ppc64/iSeries/vio.h index 3e5766a..614088f 100644 --- a/include/asm-ppc64/iSeries/vio.h +++ b/include/asm-ppc64/iSeries/vio.h @@ -8,32 +8,32 @@ * Colin Devilbiss * * (C) Copyright 2000 IBM Corporation - * + * * This header file is used by the iSeries virtual I/O device * drivers. It defines the interfaces to the common functions * (implemented in drivers/char/viopath.h) as well as defining - * common functions and structures. Currently (at the time I + * common functions and structures. Currently (at the time I * wrote this comment) the iSeries virtual I/O device drivers - * that use this are - * drivers/block/viodasd.c + * that use this are + * drivers/block/viodasd.c * drivers/char/viocons.c * drivers/char/viotape.c * drivers/cdrom/viocd.c * * The iSeries virtual ethernet support (veth.c) uses a whole * different set of functions. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) anyu later version. * * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of + * 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. + * General Public License for more details. * - * You should have received a copy of the GNU General Public License + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * @@ -44,14 +44,16 @@ #include #include -/* iSeries virtual I/O events use the subtype field in +/* + * iSeries virtual I/O events use the subtype field in * HvLpEvent to figure out what kind of vio event is coming * in. We use a table to route these, and this defines * the maximum number of distinct subtypes */ #define VIO_MAX_SUBTYPES 8 -/* Each subtype can register a handler to process their events. +/* + * Each subtype can register a handler to process their events. * The handler must have this interface. */ typedef void (vio_event_handler_t) (struct HvLpEvent * event); @@ -70,13 +72,13 @@ void vio_free_event_buffer(int subtype, void *buffer); extern HvLpIndex viopath_hostLp; extern HvLpIndex viopath_ourLp; -#define VIOCHAR_MAX_DATA 200 +#define VIOCHAR_MAX_DATA 200 -#define VIOMAJOR_SUBTYPE_MASK 0xff00 -#define VIOMINOR_SUBTYPE_MASK 0x00ff -#define VIOMAJOR_SUBTYPE_SHIFT 8 +#define VIOMAJOR_SUBTYPE_MASK 0xff00 +#define VIOMINOR_SUBTYPE_MASK 0x00ff +#define VIOMAJOR_SUBTYPE_SHIFT 8 -#define VIOVERSION 0x0101 +#define VIOVERSION 0x0101 /* * This is the general structure for VIO errors; each module should have @@ -89,8 +91,8 @@ struct vio_error_entry { int errno; const char *msg; }; -const struct vio_error_entry *vio_lookup_rc(const struct vio_error_entry - *local_table, u16 rc); +extern const struct vio_error_entry *vio_lookup_rc( + const struct vio_error_entry *local_table, u16 rc); enum viosubtypes { viomajorsubtype_monitor = 0x0100, @@ -102,7 +104,6 @@ enum viosubtypes { viomajorsubtype_scsi = 0x0700 }; - enum vioconfigsubtype { vioconfigget = 0x0001, }; -- cgit v0.10.2 From 6b7feecb2f8fcab184a38916d10349bd6648e0bc Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:35 -0700 Subject: [PATCH] ppc64 iSeries: obvious code simplifications This patch does some obvious code cleanups in the iSeries headers files. - simplifies the bodies of lots of inline functions - parenthesises a macros result - removes C++ wrapping - adds "extern" to some function declarations There are no semantic changes. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-ppc64/iSeries/HvCallCfg.h b/include/asm-ppc64/iSeries/HvCallCfg.h index 2223a96..aa491c3 100644 --- a/include/asm-ppc64/iSeries/HvCallCfg.h +++ b/include/asm-ppc64/iSeries/HvCallCfg.h @@ -69,37 +69,27 @@ enum HvCallCfg_ReqQual { static inline HvLpIndex HvCallCfg_getLps(void) { - HvLpIndex retVal = HvCall0(HvCallCfgGetLps); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall0(HvCallCfgGetLps); } static inline int HvCallCfg_isBusDedicated(u64 busIndex) { - int retVal = HvCall1(HvCallCfgIsBusDedicated,busIndex); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall1(HvCallCfgIsBusDedicated, busIndex); } static inline HvLpIndex HvCallCfg_getBusOwner(u64 busIndex) { - HvLpIndex retVal = HvCall1(HvCallCfgGetBusOwner,busIndex); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall1(HvCallCfgGetBusOwner, busIndex); } static inline HvLpIndexMap HvCallCfg_getBusAllocation(u64 busIndex) { - HvLpIndexMap retVal = HvCall1(HvCallCfgGetBusAllocation,busIndex); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall1(HvCallCfgGetBusAllocation, busIndex); } static inline HvLpIndexMap HvCallCfg_getActiveLpMap(void) { - HvLpIndexMap retVal = HvCall0(HvCallCfgGetActiveLpMap); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall0(HvCallCfgGetActiveLpMap); } static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap( @@ -112,23 +102,18 @@ static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap( u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp); if (retVal == -1) retVal = 0; - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return retVal; } static inline u64 HvCallCfg_getSystemMsChunks(void) { - u64 retVal = HvCall0(HvCallCfgGetSystemMsChunks); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall0(HvCallCfgGetSystemMsChunks); } static inline u64 HvCallCfg_getMsChunks(HvLpIndex lp, enum HvCallCfg_ReqQual qual) { - u64 retVal = HvCall2(HvCallCfgGetMsChunks,lp,qual); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall2(HvCallCfgGetMsChunks, lp, qual); } static inline u64 HvCallCfg_getMinRuntimeMsChunks(HvLpIndex lp) @@ -142,65 +127,51 @@ static inline u64 HvCallCfg_getMinRuntimeMsChunks(HvLpIndex lp) static inline u64 HvCallCfg_setMinRuntimeMsChunks(u64 chunks) { - u64 retVal = HvCall1(HvCallCfgSetMinRuntimeMsChunks,chunks); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall1(HvCallCfgSetMinRuntimeMsChunks, chunks); } static inline u64 HvCallCfg_getSystemPhysicalProcessors(void) { - u64 retVal = HvCall0(HvCallCfgGetSystemPhysicalProcessors); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall0(HvCallCfgGetSystemPhysicalProcessors); } static inline u64 HvCallCfg_getPhysicalProcessors(HvLpIndex lp, enum HvCallCfg_ReqQual qual) { - u64 retVal = HvCall2(HvCallCfgGetPhysicalProcessors,lp,qual); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall2(HvCallCfgGetPhysicalProcessors, lp, qual); } static inline u64 HvCallCfg_getConfiguredBusUnitsForInterruptProc(HvLpIndex lp, u16 hvLogicalProcIndex) { - u64 retVal = HvCall2(HvCallCfgGetConfiguredBusUnitsForIntProc,lp,hvLogicalProcIndex); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall2(HvCallCfgGetConfiguredBusUnitsForIntProc, lp, + hvLogicalProcIndex); } static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp) { - HvLpSharedPoolIndex retVal = - HvCall1(HvCallCfgGetSharedPoolIndex,lp); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall1(HvCallCfgGetSharedPoolIndex, lp); } static inline u64 HvCallCfg_getSharedProcUnits(HvLpIndex lp, enum HvCallCfg_ReqQual qual) { - u64 retVal = HvCall2(HvCallCfgGetSharedProcUnits,lp,qual); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall2(HvCallCfgGetSharedProcUnits, lp, qual); } static inline u64 HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) { - u16 retVal = HvCall1(HvCallCfgGetNumProcsInSharedPool,sPI); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); + u16 retVal = HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); return retVal; } static inline HvLpIndex HvCallCfg_getHostingLpIndex(HvLpIndex lp) { - u64 retVal = HvCall1(HvCallCfgGetHostingLpIndex,lp); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); + u64 retVal = HvCall1(HvCallCfgGetHostingLpIndex, lp); return retVal; } diff --git a/include/asm-ppc64/iSeries/HvCallEvent.h b/include/asm-ppc64/iSeries/HvCallEvent.h index a595478..5d9a327 100644 --- a/include/asm-ppc64/iSeries/HvCallEvent.h +++ b/include/asm-ppc64/iSeries/HvCallEvent.h @@ -82,13 +82,11 @@ typedef u64 HvLpDma_Rc; static inline void HvCallEvent_getOverflowLpEvents(u8 queueIndex) { HvCall1(HvCallEventGetOverflowLpEvents, queueIndex); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline void HvCallEvent_setInterLpQueueIndex(u8 queueIndex) { HvCall1(HvCallEventSetInterLpQueueIndex, queueIndex); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline void HvCallEvent_setLpEventStack(u8 queueIndex, @@ -99,7 +97,6 @@ static inline void HvCallEvent_setLpEventStack(u8 queueIndex, abs_addr = virt_to_abs(eventStackAddr); HvCall3(HvCallEventSetLpEventStack, queueIndex, abs_addr, eventStackSize); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline void HvCallEvent_setLpEventQueueInterruptProc(u8 queueIndex, @@ -107,22 +104,18 @@ static inline void HvCallEvent_setLpEventQueueInterruptProc(u8 queueIndex, { HvCall2(HvCallEventSetLpEventQueueInterruptProc, queueIndex, lpLogicalProcIndex); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline HvLpEvent_Rc HvCallEvent_signalLpEvent(struct HvLpEvent *event) { u64 abs_addr; - HvLpEvent_Rc retVal; #ifdef DEBUG_SENDEVENT printk("HvCallEvent_signalLpEvent: *event = %016lx\n ", (unsigned long)event); #endif abs_addr = virt_to_abs(event); - retVal = (HvLpEvent_Rc)HvCall1(HvCallEventSignalLpEvent, abs_addr); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall1(HvCallEventSignalLpEvent, abs_addr); } static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp, @@ -132,8 +125,6 @@ static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp, u64 eventData1, u64 eventData2, u64 eventData3, u64 eventData4, u64 eventData5) { - HvLpEvent_Rc retVal; - /* Pack the misc bits into a single Dword to pass to PLIC */ union { struct HvCallEvent_PackedParms parms; @@ -148,67 +139,49 @@ static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp, packed.parms.xSourceInstId = sourceInstanceId; packed.parms.xTargetInstId = targetInstanceId; - retVal = (HvLpEvent_Rc)HvCall7(HvCallEventSignalLpEventParms, - packed.dword, correlationToken, eventData1,eventData2, - eventData3,eventData4, eventData5); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall7(HvCallEventSignalLpEventParms, packed.dword, + correlationToken, eventData1, eventData2, + eventData3, eventData4, eventData5); } static inline HvLpEvent_Rc HvCallEvent_ackLpEvent(struct HvLpEvent *event) { u64 abs_addr; - HvLpEvent_Rc retVal; abs_addr = virt_to_abs(event); - retVal = (HvLpEvent_Rc)HvCall1(HvCallEventAckLpEvent, abs_addr); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall1(HvCallEventAckLpEvent, abs_addr); } static inline HvLpEvent_Rc HvCallEvent_cancelLpEvent(struct HvLpEvent *event) { u64 abs_addr; - HvLpEvent_Rc retVal; abs_addr = virt_to_abs(event); - retVal = (HvLpEvent_Rc)HvCall1(HvCallEventCancelLpEvent, abs_addr); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall1(HvCallEventCancelLpEvent, abs_addr); } static inline HvLpInstanceId HvCallEvent_getSourceLpInstanceId( HvLpIndex targetLp, HvLpEvent_Type type) { - HvLpInstanceId retVal; - - retVal = HvCall2(HvCallEventGetSourceLpInstanceId, targetLp, type); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall2(HvCallEventGetSourceLpInstanceId, targetLp, type); } static inline HvLpInstanceId HvCallEvent_getTargetLpInstanceId( HvLpIndex targetLp, HvLpEvent_Type type) { - HvLpInstanceId retVal; - - retVal = HvCall2(HvCallEventGetTargetLpInstanceId, targetLp, type); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall2(HvCallEventGetTargetLpInstanceId, targetLp, type); } static inline void HvCallEvent_openLpEventPath(HvLpIndex targetLp, HvLpEvent_Type type) { HvCall2(HvCallEventOpenLpEventPath, targetLp, type); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline void HvCallEvent_closeLpEventPath(HvLpIndex targetLp, HvLpEvent_Type type) { HvCall2(HvCallEventCloseLpEventPath, targetLp, type); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline HvLpDma_Rc HvCallEvent_dmaBufList(HvLpEvent_Type type, @@ -220,7 +193,6 @@ static inline HvLpDma_Rc HvCallEvent_dmaBufList(HvLpEvent_Type type, /* Do these need to be converted to absolute addresses? */ u64 localBufList, u64 remoteBufList, u32 transferLength) { - HvLpDma_Rc retVal; /* Pack the misc bits into a single Dword to pass to PLIC */ union { struct HvCallEvent_PackedDmaParms parms; @@ -237,11 +209,8 @@ static inline HvLpDma_Rc HvCallEvent_dmaBufList(HvLpEvent_Type type, packed.parms.xLocalInstId = localInstanceId; packed.parms.xRemoteInstId = remoteInstanceId; - retVal = (HvLpDma_Rc)HvCall4(HvCallEventDmaBufList, - packed.dword, localBufList, remoteBufList, - transferLength); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall4(HvCallEventDmaBufList, packed.dword, localBufList, + remoteBufList, transferLength); } static inline HvLpDma_Rc HvCallEvent_dmaSingle(HvLpEvent_Type type, @@ -252,7 +221,6 @@ static inline HvLpDma_Rc HvCallEvent_dmaSingle(HvLpEvent_Type type, HvLpDma_AddressType remoteAddressType, u64 localAddrOrTce, u64 remoteAddrOrTce, u32 transferLength) { - HvLpDma_Rc retVal; /* Pack the misc bits into a single Dword to pass to PLIC */ union { struct HvCallEvent_PackedDmaParms parms; @@ -269,24 +237,17 @@ static inline HvLpDma_Rc HvCallEvent_dmaSingle(HvLpEvent_Type type, packed.parms.xLocalInstId = localInstanceId; packed.parms.xRemoteInstId = remoteInstanceId; - retVal = (HvLpDma_Rc)HvCall4(HvCallEventDmaSingle, - packed.dword, localAddrOrTce, remoteAddrOrTce, - transferLength); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return (HvLpDma_Rc)HvCall4(HvCallEventDmaSingle, packed.dword, + localAddrOrTce, remoteAddrOrTce, transferLength); } static inline HvLpDma_Rc HvCallEvent_dmaToSp(void *local, u32 remote, u32 length, HvLpDma_Direction dir) { u64 abs_addr; - HvLpDma_Rc retVal; abs_addr = virt_to_abs(local); - retVal = (HvLpDma_Rc)HvCall4(HvCallEventDmaToSp, abs_addr, remote, - length, dir); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall4(HvCallEventDmaToSp, abs_addr, remote, length, dir); } #endif /* _HVCALLEVENT_H */ diff --git a/include/asm-ppc64/iSeries/HvCallHpt.h b/include/asm-ppc64/iSeries/HvCallHpt.h index 827d26c..66f3822 100644 --- a/include/asm-ppc64/iSeries/HvCallHpt.h +++ b/include/asm-ppc64/iSeries/HvCallHpt.h @@ -43,34 +43,27 @@ static inline u64 HvCallHpt_getHptAddress(void) { - u64 retval = HvCall0(HvCallHptGetHptAddress); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retval; + return HvCall0(HvCallHptGetHptAddress); } static inline u64 HvCallHpt_getHptPages(void) { - u64 retval = HvCall0(HvCallHptGetHptPages); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retval; + return HvCall0(HvCallHptGetHptPages); } static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value) { HvCall2(HvCallHptSetPp, hpteIndex, value); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff) { HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex) { HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, @@ -81,36 +74,30 @@ static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet, hpteIndex, bitson, bitsoff, 1); HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); return compressedStatus; } static inline u64 HvCallHpt_findValid(HPTE *hpte, u64 vpn) { - u64 retIndex = HvCall3Ret16( HvCallHptFindValid, hpte, vpn, 0, 0 ); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retIndex; + return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0); } static inline u64 HvCallHpt_findNextValid(HPTE *hpte, u32 hpteIndex, u8 bitson, u8 bitsoff) { - u64 retIndex = HvCall3Ret16( HvCallHptFindNextValid, hpte, hpteIndex, bitson, bitsoff ); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retIndex; + return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex, + bitson, bitsoff); } static inline void HvCallHpt_get(HPTE *hpte, u32 hpteIndex) { HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, HPTE *hpte) { HvCall4(HvCallHptAddValidate, hpteIndex, hBit, (*((u64 *)hpte)), (*(((u64 *)hpte)+1))); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } #endif /* _HVCALLHPT_H */ diff --git a/include/asm-ppc64/iSeries/HvCallPci.h b/include/asm-ppc64/iSeries/HvCallPci.h index 346ab5d..c8d675c 100644 --- a/include/asm-ppc64/iSeries/HvCallPci.h +++ b/include/asm-ppc64/iSeries/HvCallPci.h @@ -140,8 +140,6 @@ static inline u64 HvCallPci_configLoad8(u16 busNumber, u8 subBusNumber, HvCall3Ret16(HvCallPciConfigLoad8, &retVal, *(u64 *)&dsa, offset, 0); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - *value = retVal.value; return retVal.rc; @@ -161,8 +159,6 @@ static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber, HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - *value = retVal.value; return retVal.rc; @@ -182,8 +178,6 @@ static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - *value = retVal.value; return retVal.rc; @@ -193,7 +187,6 @@ static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, u8 deviceId, u32 offset, u8 value) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -201,18 +194,13 @@ static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, dsa.subBusNumber = subBusNumber; dsa.deviceId = deviceId; - retVal = HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0); } static inline u64 HvCallPci_configStore16(u16 busNumber, u8 subBusNumber, u8 deviceId, u32 offset, u16 value) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -220,18 +208,13 @@ static inline u64 HvCallPci_configStore16(u16 busNumber, u8 subBusNumber, dsa.subBusNumber = subBusNumber; dsa.deviceId = deviceId; - retVal = HvCall4(HvCallPciConfigStore16, *(u64 *)&dsa, offset, value, 0); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall4(HvCallPciConfigStore16, *(u64 *)&dsa, offset, value, 0); } static inline u64 HvCallPci_configStore32(u16 busNumber, u8 subBusNumber, u8 deviceId, u32 offset, u32 value) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -239,11 +222,7 @@ static inline u64 HvCallPci_configStore32(u16 busNumber, u8 subBusNumber, dsa.subBusNumber = subBusNumber; dsa.deviceId = deviceId; - retVal = HvCall4(HvCallPciConfigStore32, *(u64 *)&dsa, offset, value, 0); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall4(HvCallPciConfigStore32, *(u64 *)&dsa, offset, value, 0); } static inline u64 HvCallPci_barLoad8(u16 busNumberParm, u8 subBusParm, @@ -262,8 +241,6 @@ static inline u64 HvCallPci_barLoad8(u16 busNumberParm, u8 subBusParm, HvCall3Ret16(HvCallPciBarLoad8, &retVal, *(u64 *)&dsa, offsetParm, 0); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - *valueParm = retVal.value; return retVal.rc; @@ -285,8 +262,6 @@ static inline u64 HvCallPci_barLoad16(u16 busNumberParm, u8 subBusParm, HvCall3Ret16(HvCallPciBarLoad16, &retVal, *(u64 *)&dsa, offsetParm, 0); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - *valueParm = retVal.value; return retVal.rc; @@ -308,8 +283,6 @@ static inline u64 HvCallPci_barLoad32(u16 busNumberParm, u8 subBusParm, HvCall3Ret16(HvCallPciBarLoad32, &retVal, *(u64 *)&dsa, offsetParm, 0); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - *valueParm = retVal.value; return retVal.rc; @@ -331,8 +304,6 @@ static inline u64 HvCallPci_barLoad64(u16 busNumberParm, u8 subBusParm, HvCall3Ret16(HvCallPciBarLoad64, &retVal, *(u64 *)&dsa, offsetParm, 0); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - *valueParm = retVal.value; return retVal.rc; @@ -343,7 +314,6 @@ static inline u64 HvCallPci_barStore8(u16 busNumberParm, u8 subBusParm, u8 valueParm) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -352,11 +322,8 @@ static inline u64 HvCallPci_barStore8(u16 busNumberParm, u8 subBusParm, dsa.deviceId = deviceIdParm; dsa.barNumber = barNumberParm; - retVal = HvCall4(HvCallPciBarStore8, *(u64 *)&dsa, offsetParm, valueParm, 0); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall4(HvCallPciBarStore8, *(u64 *)&dsa, offsetParm, + valueParm, 0); } static inline u64 HvCallPci_barStore16(u16 busNumberParm, u8 subBusParm, @@ -364,7 +331,6 @@ static inline u64 HvCallPci_barStore16(u16 busNumberParm, u8 subBusParm, u16 valueParm) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -373,11 +339,8 @@ static inline u64 HvCallPci_barStore16(u16 busNumberParm, u8 subBusParm, dsa.deviceId = deviceIdParm; dsa.barNumber = barNumberParm; - retVal = HvCall4(HvCallPciBarStore16, *(u64 *)&dsa, offsetParm, valueParm, 0); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall4(HvCallPciBarStore16, *(u64 *)&dsa, offsetParm, + valueParm, 0); } static inline u64 HvCallPci_barStore32(u16 busNumberParm, u8 subBusParm, @@ -385,7 +348,6 @@ static inline u64 HvCallPci_barStore32(u16 busNumberParm, u8 subBusParm, u32 valueParm) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -394,11 +356,8 @@ static inline u64 HvCallPci_barStore32(u16 busNumberParm, u8 subBusParm, dsa.deviceId = deviceIdParm; dsa.barNumber = barNumberParm; - retVal = HvCall4(HvCallPciBarStore32, *(u64 *)&dsa, offsetParm, valueParm, 0); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall4(HvCallPciBarStore32, *(u64 *)&dsa, offsetParm, + valueParm, 0); } static inline u64 HvCallPci_barStore64(u16 busNumberParm, u8 subBusParm, @@ -406,7 +365,6 @@ static inline u64 HvCallPci_barStore64(u16 busNumberParm, u8 subBusParm, u64 valueParm) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -415,11 +373,8 @@ static inline u64 HvCallPci_barStore64(u16 busNumberParm, u8 subBusParm, dsa.deviceId = deviceIdParm; dsa.barNumber = barNumberParm; - retVal = HvCall4(HvCallPciBarStore64, *(u64 *)&dsa, offsetParm, valueParm, 0); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall4(HvCallPciBarStore64, *(u64 *)&dsa, offsetParm, + valueParm, 0); } static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm, @@ -436,8 +391,6 @@ static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm, HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal.rc; } @@ -445,7 +398,6 @@ static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm, u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -454,18 +406,13 @@ static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm, dsa.deviceId = deviceIdParm; dsa.barNumber = barNumberParm; - retVal = HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms); } static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm, u8 deviceIdParm, u64 fisrMask) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -473,18 +420,13 @@ static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm, dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; - retVal = HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask); } static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm, u8 deviceIdParm, u64 fisrMask) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -492,18 +434,13 @@ static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm, dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; - retVal = HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask); } static inline u64 HvCallPci_setSlotReset(u16 busNumberParm, u8 subBusParm, u8 deviceIdParm, u64 onNotOff) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -511,18 +448,13 @@ static inline u64 HvCallPci_setSlotReset(u16 busNumberParm, u8 subBusParm, dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; - retVal = HvCall2(HvCallPciSetSlotReset, *(u64*)&dsa, onNotOff); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall2(HvCallPciSetSlotReset, *(u64*)&dsa, onNotOff); } static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm, u8 deviceNumberParm, u64 parms, u32 sizeofParms) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -530,18 +462,13 @@ static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm, dsa.subBusNumber = subBusParm; dsa.deviceId = deviceNumberParm << 4; - retVal = HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms); } static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm, u8 deviceIdParm, u64 interruptMask) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -549,18 +476,13 @@ static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm, dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; - retVal = HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask); } static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm, u8 deviceIdParm, u64 interruptMask) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -568,18 +490,13 @@ static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm, dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; - retVal = HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask); } static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm, u8 deviceIdParm, u64 parms, u32 sizeofParms) { struct HvCallPci_DsaAddr dsa; - u64 retVal; *((u64*)&dsa) = 0; @@ -587,37 +504,30 @@ static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm, dsa.subBusNumber = subBusParm; dsa.deviceId = deviceIdParm; - retVal = HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms, sizeofParms); - - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - - return retVal; + return HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms, + sizeofParms); } static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, u16 sizeParm) { - int xRetSize; - u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, sizeParm, HvCallPci_BusVpd); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); + u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, + sizeParm, HvCallPci_BusVpd); if (xRc == -1) - xRetSize = -1; + return -1; else - xRetSize = xRc & 0xFFFF; - return xRetSize; + return xRc & 0xFFFF; } static inline int HvCallPci_getBusAdapterVpd(u16 busNumParm, u64 destParm, u16 sizeParm) { - int xRetSize; - u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, sizeParm, HvCallPci_BusAdapterVpd); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); + u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, + sizeParm, HvCallPci_BusAdapterVpd); if (xRc == -1) - xRetSize = -1; + return -1; else - xRetSize = xRc & 0xFFFF; - return xRetSize; + return xRc & 0xFFFF; } #endif /* _HVCALLPCI_H */ diff --git a/include/asm-ppc64/iSeries/HvCallSm.h b/include/asm-ppc64/iSeries/HvCallSm.h index ef6b303..8a3dbb0 100644 --- a/include/asm-ppc64/iSeries/HvCallSm.h +++ b/include/asm-ppc64/iSeries/HvCallSm.h @@ -32,10 +32,7 @@ static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex, u64 indexIntoBitMap) { - u64 retval = HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, - indexIntoBitMap ); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retval; + return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap); } #endif /* _HVCALLSM_H */ diff --git a/include/asm-ppc64/iSeries/HvCallXm.h b/include/asm-ppc64/iSeries/HvCallXm.h index a99f29b..1362a42 100644 --- a/include/asm-ppc64/iSeries/HvCallXm.h +++ b/include/asm-ppc64/iSeries/HvCallXm.h @@ -19,58 +19,43 @@ static inline void HvCallXm_getTceTableParms(u64 cb) { HvCall1(HvCallXmGetTceTableParms, cb); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); } static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce) { - u64 retval = HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce ); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retval; + return HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce); } static inline u64 HvCallXm_setTces(u64 tceTableToken, u64 tceOffset, u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4) { - u64 retval = HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces, - tce1, tce2, tce3, tce4 ); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retval; + return HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces, + tce1, tce2, tce3, tce4); } static inline u64 HvCallXm_testBus(u16 busNumber) { - u64 retVal = HvCall1(HvCallXmTestBus, busNumber); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall1(HvCallXmTestBus, busNumber); } static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber, u8 deviceId) { - u64 busUnitNumber = (subBusNumber << 8) | deviceId; - u64 retVal = HvCall2(HvCallXmTestBusUnit, busNumber, busUnitNumber); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall2(HvCallXmTestBusUnit, busNumber, + (subBusNumber << 8) | deviceId); } static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber, u8 deviceId, u64 interruptToken) { - u64 busUnitNumber = (subBusNumber << 8) | deviceId; - u64 queueIndex = 0; // HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard)); - - u64 retVal = HvCall5(HvCallXmConnectBusUnit, busNumber, busUnitNumber, - interruptToken, 0, queueIndex); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall5(HvCallXmConnectBusUnit, busNumber, + (subBusNumber << 8) | deviceId, interruptToken, 0, + 0 /* HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard)) */); } static inline u64 HvCallXm_loadTod(void) { - u64 retVal = HvCall0(HvCallXmLoadTod); - // getPaca()->adjustHmtForNoOfSpinLocksHeld(); - return retVal; + return HvCall0(HvCallXmLoadTod); } #endif /* _HVCALLXM_H */ diff --git a/include/asm-ppc64/iSeries/HvLpConfig.h b/include/asm-ppc64/iSeries/HvLpConfig.h index 47311cc..8176980 100644 --- a/include/asm-ppc64/iSeries/HvLpConfig.h +++ b/include/asm-ppc64/iSeries/HvLpConfig.h @@ -281,8 +281,7 @@ static inline u64 HvLpConfig_getLoadPages(void) static inline int HvLpConfig_isBusOwnedByThisLp(HvBusNumber busNumber) { - HvLpIndex busOwner = HvLpConfig_getBusOwner(busNumber); - return (busOwner == HvLpConfig_getLpIndex()); + return (HvLpConfig_getBusOwner(busNumber) == HvLpConfig_getLpIndex()); } static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, diff --git a/include/asm-ppc64/iSeries/XmPciLpEvent.h b/include/asm-ppc64/iSeries/XmPciLpEvent.h index 9c80079..4936627 100644 --- a/include/asm-ppc64/iSeries/XmPciLpEvent.h +++ b/include/asm-ppc64/iSeries/XmPciLpEvent.h @@ -1,15 +1,7 @@ #ifndef __XMPCILPEVENT_H__ #define __XMPCILPEVENT_H__ -#ifdef __cplusplus -extern "C" { -#endif - -int XmPciLpEvent_init(void); -void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); - -#ifdef __cplusplus -} -#endif +extern int XmPciLpEvent_init(void); +extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); #endif /* __XMPCILPEVENT_H__ */ diff --git a/include/asm-ppc64/iSeries/iSeries_irq.h b/include/asm-ppc64/iSeries/iSeries_irq.h index ff8dded..fbd5f52 100644 --- a/include/asm-ppc64/iSeries/iSeries_irq.h +++ b/include/asm-ppc64/iSeries/iSeries_irq.h @@ -1,19 +1,11 @@ #ifndef __ISERIES_IRQ_H__ #define __ISERIES_IRQ_H__ -#ifdef __cplusplus -extern "C" { -#endif +extern void iSeries_init_IRQ(void); +extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId); +extern int iSeries_assign_IRQ(int, HvBusNumber, HvSubBusNumber, HvAgentId); +extern void iSeries_activate_IRQs(void); -void iSeries_init_IRQ(void); -int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId); -int iSeries_assign_IRQ(int, HvBusNumber, HvSubBusNumber, HvAgentId); -void iSeries_activate_IRQs(void); - -int XmPciLpEvent_init(void); - -#ifdef __cplusplus -} -#endif +extern int XmPciLpEvent_init(void); #endif /* __ISERIES_IRQ_H__ */ diff --git a/include/asm-ppc64/iSeries/iSeries_pci.h b/include/asm-ppc64/iSeries/iSeries_pci.h index 9c6d645..f45cd8a 100644 --- a/include/asm-ppc64/iSeries/iSeries_pci.h +++ b/include/asm-ppc64/iSeries/iSeries_pci.h @@ -55,7 +55,7 @@ struct iSeries_Device_Node; */ #define ISERIES_PCI_AGENTID(idsel, func) \ - ((idsel & 0x0F) << 4) | (func & 0x07) + (((idsel & 0x0F) << 4) | (func & 0x07)) #define ISERIES_ENCODE_DEVICE(agentid) \ ((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07)) diff --git a/include/asm-ppc64/iSeries/vio.h b/include/asm-ppc64/iSeries/vio.h index 614088f..6c05e625 100644 --- a/include/asm-ppc64/iSeries/vio.h +++ b/include/asm-ppc64/iSeries/vio.h @@ -58,16 +58,16 @@ */ typedef void (vio_event_handler_t) (struct HvLpEvent * event); -int viopath_open(HvLpIndex remoteLp, int subtype, int numReq); -int viopath_close(HvLpIndex remoteLp, int subtype, int numReq); -int vio_setHandler(int subtype, vio_event_handler_t * beh); -int vio_clearHandler(int subtype); -int viopath_isactive(HvLpIndex lp); -HvLpInstanceId viopath_sourceinst(HvLpIndex lp); -HvLpInstanceId viopath_targetinst(HvLpIndex lp); -void vio_set_hostlp(void); -void *vio_get_event_buffer(int subtype); -void vio_free_event_buffer(int subtype, void *buffer); +extern int viopath_open(HvLpIndex remoteLp, int subtype, int numReq); +extern int viopath_close(HvLpIndex remoteLp, int subtype, int numReq); +extern int vio_setHandler(int subtype, vio_event_handler_t * beh); +extern int vio_clearHandler(int subtype); +extern int viopath_isactive(HvLpIndex lp); +extern HvLpInstanceId viopath_sourceinst(HvLpIndex lp); +extern HvLpInstanceId viopath_targetinst(HvLpIndex lp); +extern void vio_set_hostlp(void); +extern void *vio_get_event_buffer(int subtype); +extern void vio_free_event_buffer(int subtype, void *buffer); extern HvLpIndex viopath_hostLp; extern HvLpIndex viopath_ourLp; -- cgit v0.10.2 From 0bc0ffd5f0854b9143606684fb925f4290ae13e7 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:36 -0700 Subject: [PATCH] ppc64 iSeries: remove LparData.h include/asm-ppc64/iSeries/LparData.h just included a whole lot of other files to declare variables that would be better declared in those other files. So, remove it. This will reduce that number of things needed to be included in most cases to access the relevant variables. Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/HvLpEvent.c b/arch/ppc64/kernel/HvLpEvent.c index f8f1963..90032b1 100644 --- a/arch/ppc64/kernel/HvLpEvent.c +++ b/arch/ppc64/kernel/HvLpEvent.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* Array of LpEvent handler functions */ LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; diff --git a/arch/ppc64/kernel/ItLpQueue.c b/arch/ppc64/kernel/ItLpQueue.c index c923a81..cdea00d 100644 --- a/arch/ppc64/kernel/ItLpQueue.c +++ b/arch/ppc64/kernel/ItLpQueue.c @@ -16,7 +16,6 @@ #include #include #include -#include static __inline__ int set_inUse( struct ItLpQueue * lpQueue ) { diff --git a/arch/ppc64/kernel/iSeries_VpdInfo.c b/arch/ppc64/kernel/iSeries_VpdInfo.c index a6f0ff2..a82caf9 100644 --- a/arch/ppc64/kernel/iSeries_VpdInfo.c +++ b/arch/ppc64/kernel/iSeries_VpdInfo.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include "pci.h" diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c index bd4c255..9829cd4 100644 --- a/arch/ppc64/kernel/iSeries_pci.c +++ b/arch/ppc64/kernel/iSeries_pci.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/iSeries_proc.c b/arch/ppc64/kernel/iSeries_proc.c index bf85a1f..356bd99 100644 --- a/arch/ppc64/kernel/iSeries_proc.c +++ b/arch/ppc64/kernel/iSeries_proc.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include static int __init iseries_proc_create(void) { diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index e80cfc5..3d3ed63 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include @@ -58,6 +58,9 @@ #include #include #include +#include +#include +#include extern void hvlog(char *fmt, ...); diff --git a/arch/ppc64/kernel/iSeries_smp.c b/arch/ppc64/kernel/iSeries_smp.c index ba1f084..ff2281b 100644 --- a/arch/ppc64/kernel/iSeries_smp.c +++ b/arch/ppc64/kernel/iSeries_smp.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c index 4fd7f20..d860467 100644 --- a/arch/ppc64/kernel/irq.c +++ b/arch/ppc64/kernel/irq.c @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c index a8fd32d..387923f 100644 --- a/arch/ppc64/kernel/lparcfg.c +++ b/arch/ppc64/kernel/lparcfg.c @@ -28,12 +28,12 @@ #include #include #include -#include #include #include #include #include #include +#include #define MODULE_VERS "1.6" #define MODULE_NAME "lparcfg" diff --git a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c index 1c4c796..3c00f7b 100644 --- a/arch/ppc64/kernel/ras.c +++ b/arch/ppc64/kernel/ras.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c index 6798905..4cdafb4 100644 --- a/arch/ppc64/kernel/rtc.c +++ b/arch/ppc64/kernel/rtc.c @@ -42,7 +42,6 @@ #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index dce198d..8e439a8 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -57,6 +56,8 @@ #include #include #include +#include +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/ppc64/kernel/viopath.c b/arch/ppc64/kernel/viopath.c index 8caa078..4e5c36e 100644 --- a/arch/ppc64/kernel/viopath.c +++ b/arch/ppc64/kernel/viopath.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/asm-ppc64/iSeries/HvLpConfig.h b/include/asm-ppc64/iSeries/HvLpConfig.h index 8176980..9411b5a 100644 --- a/include/asm-ppc64/iSeries/HvLpConfig.h +++ b/include/asm-ppc64/iSeries/HvLpConfig.h @@ -27,7 +27,6 @@ #include #include #include -#include extern HvLpIndex HvLpConfig_getLpIndex_outline(void); diff --git a/include/asm-ppc64/iSeries/HvReleaseData.h b/include/asm-ppc64/iSeries/HvReleaseData.h index c0cd21c..01a1f13 100644 --- a/include/asm-ppc64/iSeries/HvReleaseData.h +++ b/include/asm-ppc64/iSeries/HvReleaseData.h @@ -58,4 +58,6 @@ struct HvReleaseData { char xRsvd3[20]; /* Reserved x2C-x3F */ }; +extern struct HvReleaseData hvReleaseData; + #endif /* _HVRELEASEDATA_H */ diff --git a/include/asm-ppc64/iSeries/IoHriMainStore.h b/include/asm-ppc64/iSeries/IoHriMainStore.h index fbb3ee4..45ed3ea 100644 --- a/include/asm-ppc64/iSeries/IoHriMainStore.h +++ b/include/asm-ppc64/iSeries/IoHriMainStore.h @@ -161,4 +161,6 @@ struct IoHriMainStoreSegment5 { u64 reserved3; }; +extern u64 xMsVpd[]; + #endif /* _IOHRIMAINSTORE_H */ diff --git a/include/asm-ppc64/iSeries/IoHriProcessorVpd.h b/include/asm-ppc64/iSeries/IoHriProcessorVpd.h index ccb7b7c..73b73d8 100644 --- a/include/asm-ppc64/iSeries/IoHriProcessorVpd.h +++ b/include/asm-ppc64/iSeries/IoHriProcessorVpd.h @@ -81,4 +81,6 @@ struct IoHriProcessorVpd { char xProcSrc[72]; // CSP format SRC xB8-xFF }; +extern struct IoHriProcessorVpd xIoHriProcessorVpd[]; + #endif /* _IOHRIPROCESSORVPD_H */ diff --git a/include/asm-ppc64/iSeries/ItExtVpdPanel.h b/include/asm-ppc64/iSeries/ItExtVpdPanel.h index b714907..4c546a8 100644 --- a/include/asm-ppc64/iSeries/ItExtVpdPanel.h +++ b/include/asm-ppc64/iSeries/ItExtVpdPanel.h @@ -47,4 +47,6 @@ struct ItExtVpdPanel { u8 xRsvd2[48]; }; +extern struct ItExtVpdPanel xItExtVpdPanel; + #endif /* _ITEXTVPDPANEL_H */ diff --git a/include/asm-ppc64/iSeries/ItIplParmsReal.h b/include/asm-ppc64/iSeries/ItIplParmsReal.h index 14f0b0a..ae3417d 100644 --- a/include/asm-ppc64/iSeries/ItIplParmsReal.h +++ b/include/asm-ppc64/iSeries/ItIplParmsReal.h @@ -66,4 +66,6 @@ struct ItIplParmsReal { u64 xRsvd13; // Reserved x38-x3F }; +extern struct ItIplParmsReal xItIplParmsReal; + #endif /* _ITIPLPARMSREAL_H */ diff --git a/include/asm-ppc64/iSeries/ItLpNaca.h b/include/asm-ppc64/iSeries/ItLpNaca.h index 942b07d..225d017 100644 --- a/include/asm-ppc64/iSeries/ItLpNaca.h +++ b/include/asm-ppc64/iSeries/ItLpNaca.h @@ -19,6 +19,8 @@ #ifndef _ITLPNACA_H #define _ITLPNACA_H +#include + /* * This control block contains the data that is shared between the * hypervisor (PLIC) and the OS. @@ -73,4 +75,6 @@ struct ItLpNaca { u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF }; +extern struct ItLpNaca itLpNaca; + #endif /* _ITLPNACA_H */ diff --git a/include/asm-ppc64/iSeries/ItVpdAreas.h b/include/asm-ppc64/iSeries/ItVpdAreas.h index cfb9925..97cfa6c 100644 --- a/include/asm-ppc64/iSeries/ItVpdAreas.h +++ b/include/asm-ppc64/iSeries/ItVpdAreas.h @@ -90,4 +90,6 @@ struct ItVpdAreas { void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF }; +extern struct ItVpdAreas itVpdAreas; + #endif /* _ITVPDAREAS_H */ diff --git a/include/asm-ppc64/iSeries/LparData.h b/include/asm-ppc64/iSeries/LparData.h deleted file mode 100644 index a9fd6e2..0000000 --- a/include/asm-ppc64/iSeries/LparData.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * LparData.h - * Copyright (C) 2001 Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LPARDATA_H -#define _LPARDATA_H - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct LparMap xLparMap; -extern struct HvReleaseData hvReleaseData; -extern struct ItLpNaca itLpNaca; -extern struct ItIplParmsReal xItIplParmsReal; -extern struct ItExtVpdPanel xItExtVpdPanel; -extern struct IoHriProcessorVpd xIoHriProcessorVpd[]; -extern struct ItLpQueue xItLpQueue; -extern struct ItVpdAreas itVpdAreas; -extern u64 xMsVpd[]; -extern struct msChunks msChunks; - -#endif /* _LPARDATA_H */ diff --git a/include/asm-ppc64/iSeries/LparMap.h b/include/asm-ppc64/iSeries/LparMap.h index 1505c4f..038e5df 100644 --- a/include/asm-ppc64/iSeries/LparMap.h +++ b/include/asm-ppc64/iSeries/LparMap.h @@ -64,4 +64,6 @@ struct LparMap { u64 xVPN; // Virtual Page Number (0x000C000000000000) }; +extern struct LparMap xLparMap; + #endif /* _LPARMAP_H */ -- cgit v0.10.2 From dd61ce922770b299081c3e729ea65758ed676034 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:37 -0700 Subject: [PATCH] ppc64 iSeries: eliminate some unused inline functions This patch removes from the iSeries header files a large number of inline functions that are not used. It also changes the only caller of a HvCallCfg function that is outside HvLpConfig.h to its equivalent HvLpConfig function and no longer includes HvCallCfg.h where it is not needed. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/iSeries_smp.c b/arch/ppc64/kernel/iSeries_smp.c index ff2281b..f74386e 100644 --- a/arch/ppc64/kernel/iSeries_smp.c +++ b/arch/ppc64/kernel/iSeries_smp.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/viopath.c b/arch/ppc64/kernel/viopath.c index 4e5c36e..ef52404 100644 --- a/arch/ppc64/kernel/viopath.c +++ b/arch/ppc64/kernel/viopath.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include @@ -364,7 +363,7 @@ void vio_set_hostlp(void) * while we're active */ viopath_ourLp = HvLpConfig_getLpIndex(); - viopath_hostLp = HvCallCfg_getHostingLpIndex(viopath_ourLp); + viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp); if (viopath_hostLp != HvLpIndexInvalid) vio_setHandler(viomajorsubtype_config, handleConfig); diff --git a/include/asm-ppc64/iSeries/HvCallCfg.h b/include/asm-ppc64/iSeries/HvCallCfg.h index aa491c3..ddf2bb5 100644 --- a/include/asm-ppc64/iSeries/HvCallCfg.h +++ b/include/asm-ppc64/iSeries/HvCallCfg.h @@ -67,31 +67,11 @@ enum HvCallCfg_ReqQual { #define HvCallCfgGetLpExecutionMode HvCallCfg + 31 #define HvCallCfgGetHostingLpIndex HvCallCfg + 32 -static inline HvLpIndex HvCallCfg_getLps(void) -{ - return HvCall0(HvCallCfgGetLps); -} - -static inline int HvCallCfg_isBusDedicated(u64 busIndex) -{ - return HvCall1(HvCallCfgIsBusDedicated, busIndex); -} - static inline HvLpIndex HvCallCfg_getBusOwner(u64 busIndex) { return HvCall1(HvCallCfgGetBusOwner, busIndex); } -static inline HvLpIndexMap HvCallCfg_getBusAllocation(u64 busIndex) -{ - return HvCall1(HvCallCfgGetBusAllocation, busIndex); -} - -static inline HvLpIndexMap HvCallCfg_getActiveLpMap(void) -{ - return HvCall0(HvCallCfgGetActiveLpMap); -} - static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap( HvLpIndex lp) { @@ -105,31 +85,12 @@ static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap( return retVal; } -static inline u64 HvCallCfg_getSystemMsChunks(void) -{ - return HvCall0(HvCallCfgGetSystemMsChunks); -} - static inline u64 HvCallCfg_getMsChunks(HvLpIndex lp, enum HvCallCfg_ReqQual qual) { return HvCall2(HvCallCfgGetMsChunks, lp, qual); } -static inline u64 HvCallCfg_getMinRuntimeMsChunks(HvLpIndex lp) -{ - /* - * NOTE: This function was added in v5r1 so older hypervisors - * will return a -1 value - */ - return HvCall1(HvCallCfgGetMinRuntimeMsChunks, lp); -} - -static inline u64 HvCallCfg_setMinRuntimeMsChunks(u64 chunks) -{ - return HvCall1(HvCallCfgSetMinRuntimeMsChunks, chunks); -} - static inline u64 HvCallCfg_getSystemPhysicalProcessors(void) { return HvCall0(HvCallCfgGetSystemPhysicalProcessors); @@ -141,14 +102,6 @@ static inline u64 HvCallCfg_getPhysicalProcessors(HvLpIndex lp, return HvCall2(HvCallCfgGetPhysicalProcessors, lp, qual); } -static inline u64 HvCallCfg_getConfiguredBusUnitsForInterruptProc(HvLpIndex lp, - u16 hvLogicalProcIndex) -{ - return HvCall2(HvCallCfgGetConfiguredBusUnitsForIntProc, lp, - hvLogicalProcIndex); - -} - static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp) { return HvCall1(HvCallCfgGetSharedPoolIndex, lp); @@ -164,15 +117,13 @@ static inline u64 HvCallCfg_getSharedProcUnits(HvLpIndex lp, static inline u64 HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) { - u16 retVal = HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); - return retVal; + return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); } static inline HvLpIndex HvCallCfg_getHostingLpIndex(HvLpIndex lp) { - u64 retVal = HvCall1(HvCallCfgGetHostingLpIndex, lp); - return retVal; + return HvCall1(HvCallCfgGetHostingLpIndex, lp); } #endif /* _HVCALLCFG_H */ diff --git a/include/asm-ppc64/iSeries/HvLpConfig.h b/include/asm-ppc64/iSeries/HvLpConfig.h index 9411b5a..78d6828 100644 --- a/include/asm-ppc64/iSeries/HvLpConfig.h +++ b/include/asm-ppc64/iSeries/HvLpConfig.h @@ -40,127 +40,16 @@ static inline HvLpIndex HvLpConfig_getPrimaryLpIndex(void) return itLpNaca.xPrimaryLpIndex; } -static inline HvLpIndex HvLpConfig_getLps(void) -{ - return HvCallCfg_getLps(); -} - -static inline HvLpIndexMap HvLpConfig_getActiveLpMap(void) -{ - return HvCallCfg_getActiveLpMap(); -} - -static inline u64 HvLpConfig_getSystemMsMegs(void) -{ - return HvCallCfg_getSystemMsChunks() / HVCHUNKSPERMEG; -} - -static inline u64 HvLpConfig_getSystemMsChunks(void) -{ - return HvCallCfg_getSystemMsChunks(); -} - -static inline u64 HvLpConfig_getSystemMsPages(void) -{ - return HvCallCfg_getSystemMsChunks() * HVPAGESPERCHUNK; -} - -static inline u64 HvLpConfig_getMsMegs(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur) - / HVCHUNKSPERMEG; -} - static inline u64 HvLpConfig_getMsChunks(void) { return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur); } -static inline u64 HvLpConfig_getMsPages(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur) - * HVPAGESPERCHUNK; -} - -static inline u64 HvLpConfig_getMinMsMegs(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Min) - / HVCHUNKSPERMEG; -} - -static inline u64 HvLpConfig_getMinMsChunks(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Min); -} - -static inline u64 HvLpConfig_getMinMsPages(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Min) - * HVPAGESPERCHUNK; -} - -static inline u64 HvLpConfig_getMinRuntimeMsMegs(void) -{ - return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) - / HVCHUNKSPERMEG; -} - -static inline u64 HvLpConfig_getMinRuntimeMsChunks(void) -{ - return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()); -} - -static inline u64 HvLpConfig_getMinRuntimeMsPages(void) -{ - return HvCallCfg_getMinRuntimeMsChunks(HvLpConfig_getLpIndex()) - * HVPAGESPERCHUNK; -} - -static inline u64 HvLpConfig_getMaxMsMegs(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Max) - / HVCHUNKSPERMEG; -} - -static inline u64 HvLpConfig_getMaxMsChunks(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Max); -} - -static inline u64 HvLpConfig_getMaxMsPages(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Max) - * HVPAGESPERCHUNK; -} - -static inline u64 HvLpConfig_getInitMsMegs(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Init) - / HVCHUNKSPERMEG; -} - -static inline u64 HvLpConfig_getInitMsChunks(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Init); -} - -static inline u64 HvLpConfig_getInitMsPages(void) -{ - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Init) - * HVPAGESPERCHUNK; -} - static inline u64 HvLpConfig_getSystemPhysicalProcessors(void) { return HvCallCfg_getSystemPhysicalProcessors(); } -static inline u64 HvLpConfig_getSystemLogicalProcessors(void) -{ - return HvCallCfg_getSystemPhysicalProcessors() - * (/*getPaca()->getSecondaryThreadCount() +*/ 1); -} - static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) { return HvCallCfg_getNumProcsInSharedPool(sPI); @@ -172,13 +61,6 @@ static inline u64 HvLpConfig_getPhysicalProcessors(void) HvCallCfg_Cur); } -static inline u64 HvLpConfig_getLogicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Cur) - * (/*getPaca()->getSecondaryThreadCount() +*/ 1); -} - static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void) { return HvCallCfg_getSharedPoolIndex(HvLpConfig_getLpIndex()); @@ -190,57 +72,18 @@ static inline u64 HvLpConfig_getSharedProcUnits(void) HvCallCfg_Cur); } -static inline u64 HvLpConfig_getMinSharedProcUnits(void) -{ - return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), - HvCallCfg_Min); -} - static inline u64 HvLpConfig_getMaxSharedProcUnits(void) { return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), HvCallCfg_Max); } -static inline u64 HvLpConfig_getMinPhysicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Min); -} - -static inline u64 HvLpConfig_getMinLogicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Min) - * (/*getPaca()->getSecondaryThreadCount() +*/ 1); -} - static inline u64 HvLpConfig_getMaxPhysicalProcessors(void) { return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), HvCallCfg_Max); } -static inline u64 HvLpConfig_getMaxLogicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Max) - * (/*getPaca()->getSecondaryThreadCount() +*/ 1); -} - -static inline u64 HvLpConfig_getInitPhysicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Init); -} - -static inline u64 HvLpConfig_getInitLogicalProcessors(void) -{ - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), - HvCallCfg_Init) - * (/*getPaca()->getSecondaryThreadCount() +*/ 1); -} - static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) { return HvCallCfg_getVirtualLanIndexMap(HvLpConfig_getLpIndex_outline()); @@ -252,37 +95,6 @@ static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp( return HvCallCfg_getVirtualLanIndexMap(lp); } -static inline HvLpIndex HvLpConfig_getBusOwner(HvBusNumber busNumber) -{ - return HvCallCfg_getBusOwner(busNumber); -} - -static inline int HvLpConfig_isBusDedicated(HvBusNumber busNumber) -{ - return HvCallCfg_isBusDedicated(busNumber); -} - -static inline HvLpIndexMap HvLpConfig_getBusAllocation(HvBusNumber busNumber) -{ - return HvCallCfg_getBusAllocation(busNumber); -} - -/* returns the absolute real address of the load area */ -static inline u64 HvLpConfig_getLoadAddress(void) -{ - return itLpNaca.xLoadAreaAddr & 0x7fffffffffffffff; -} - -static inline u64 HvLpConfig_getLoadPages(void) -{ - return itLpNaca.xLoadAreaChunks * HVPAGESPERCHUNK; -} - -static inline int HvLpConfig_isBusOwnedByThisLp(HvBusNumber busNumber) -{ - return (HvLpConfig_getBusOwner(busNumber) == HvLpConfig_getLpIndex()); -} - static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, HvLpIndex lp2) { -- cgit v0.10.2 From 2310c977a9b7a4d08fbaa74e694b49b38d49f5ae Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:38 -0700 Subject: [PATCH] ppc64 iSeries: remove HvCallCfg.h Now that the only users of things in HvCallCfg.h are in HvLpConfig.h, merge in the bit we need and remove HvCallCfg.h. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-ppc64/iSeries/HvCallCfg.h b/include/asm-ppc64/iSeries/HvCallCfg.h deleted file mode 100644 index ddf2bb5..0000000 --- a/include/asm-ppc64/iSeries/HvCallCfg.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * HvCallCfg.h - * Copyright (C) 2001 Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from the OS. - */ -#ifndef _HVCALLCFG_H -#define _HVCALLCFG_H - -#include -#include - -enum HvCallCfg_ReqQual { - HvCallCfg_Cur = 0, - HvCallCfg_Init = 1, - HvCallCfg_Max = 2, - HvCallCfg_Min = 3 -}; - -#define HvCallCfgGetLps HvCallCfg + 0 -#define HvCallCfgGetActiveLpMap HvCallCfg + 1 -#define HvCallCfgGetLpVrmIndex HvCallCfg + 2 -#define HvCallCfgGetLpMinSupportedPlicVrmIndex HvCallCfg + 3 -#define HvCallCfgGetLpMinCompatablePlicVrmIndex HvCallCfg + 4 -#define HvCallCfgGetLpVrmName HvCallCfg + 5 -#define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6 -#define HvCallCfgGetPhysicalProcessors HvCallCfg + 7 -#define HvCallCfgGetSystemMsChunks HvCallCfg + 8 -#define HvCallCfgGetMsChunks HvCallCfg + 9 -#define HvCallCfgGetInteractivePercentage HvCallCfg + 10 -#define HvCallCfgIsBusDedicated HvCallCfg + 11 -#define HvCallCfgGetBusOwner HvCallCfg + 12 -#define HvCallCfgGetBusAllocation HvCallCfg + 13 -#define HvCallCfgGetBusUnitOwner HvCallCfg + 14 -#define HvCallCfgGetBusUnitAllocation HvCallCfg + 15 -#define HvCallCfgGetVirtualBusPool HvCallCfg + 16 -#define HvCallCfgGetBusUnitInterruptProc HvCallCfg + 17 -#define HvCallCfgGetConfiguredBusUnitsForIntProc HvCallCfg + 18 -#define HvCallCfgGetRioSanBusPool HvCallCfg + 19 -#define HvCallCfgGetSharedPoolIndex HvCallCfg + 20 -#define HvCallCfgGetSharedProcUnits HvCallCfg + 21 -#define HvCallCfgGetNumProcsInSharedPool HvCallCfg + 22 -#define HvCallCfgRouter23 HvCallCfg + 23 -#define HvCallCfgRouter24 HvCallCfg + 24 -#define HvCallCfgRouter25 HvCallCfg + 25 -#define HvCallCfgRouter26 HvCallCfg + 26 -#define HvCallCfgRouter27 HvCallCfg + 27 -#define HvCallCfgGetMinRuntimeMsChunks HvCallCfg + 28 -#define HvCallCfgSetMinRuntimeMsChunks HvCallCfg + 29 -#define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30 -#define HvCallCfgGetLpExecutionMode HvCallCfg + 31 -#define HvCallCfgGetHostingLpIndex HvCallCfg + 32 - -static inline HvLpIndex HvCallCfg_getBusOwner(u64 busIndex) -{ - return HvCall1(HvCallCfgGetBusOwner, busIndex); -} - -static inline HvLpVirtualLanIndexMap HvCallCfg_getVirtualLanIndexMap( - HvLpIndex lp) -{ - /* - * This is a new function in V5R1 so calls to this on older - * hypervisors will return -1 - */ - u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp); - if (retVal == -1) - retVal = 0; - return retVal; -} - -static inline u64 HvCallCfg_getMsChunks(HvLpIndex lp, - enum HvCallCfg_ReqQual qual) -{ - return HvCall2(HvCallCfgGetMsChunks, lp, qual); -} - -static inline u64 HvCallCfg_getSystemPhysicalProcessors(void) -{ - return HvCall0(HvCallCfgGetSystemPhysicalProcessors); -} - -static inline u64 HvCallCfg_getPhysicalProcessors(HvLpIndex lp, - enum HvCallCfg_ReqQual qual) -{ - return HvCall2(HvCallCfgGetPhysicalProcessors, lp, qual); -} - -static inline HvLpSharedPoolIndex HvCallCfg_getSharedPoolIndex(HvLpIndex lp) -{ - return HvCall1(HvCallCfgGetSharedPoolIndex, lp); - -} - -static inline u64 HvCallCfg_getSharedProcUnits(HvLpIndex lp, - enum HvCallCfg_ReqQual qual) -{ - return HvCall2(HvCallCfgGetSharedProcUnits, lp, qual); - -} - -static inline u64 HvCallCfg_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) -{ - return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); - -} - -static inline HvLpIndex HvCallCfg_getHostingLpIndex(HvLpIndex lp) -{ - return HvCall1(HvCallCfgGetHostingLpIndex, lp); -} - -#endif /* _HVCALLCFG_H */ diff --git a/include/asm-ppc64/iSeries/HvLpConfig.h b/include/asm-ppc64/iSeries/HvLpConfig.h index 78d6828..f1cf1e7 100644 --- a/include/asm-ppc64/iSeries/HvLpConfig.h +++ b/include/asm-ppc64/iSeries/HvLpConfig.h @@ -24,10 +24,26 @@ * to determine which resources should be allocated to each partition. */ -#include +#include #include #include +enum { + HvCallCfg_Cur = 0, + HvCallCfg_Init = 1, + HvCallCfg_Max = 2, + HvCallCfg_Min = 3 +}; + +#define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6 +#define HvCallCfgGetPhysicalProcessors HvCallCfg + 7 +#define HvCallCfgGetMsChunks HvCallCfg + 9 +#define HvCallCfgGetSharedPoolIndex HvCallCfg + 20 +#define HvCallCfgGetSharedProcUnits HvCallCfg + 21 +#define HvCallCfgGetNumProcsInSharedPool HvCallCfg + 22 +#define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30 +#define HvCallCfgGetHostingLpIndex HvCallCfg + 32 + extern HvLpIndex HvLpConfig_getLpIndex_outline(void); static inline HvLpIndex HvLpConfig_getLpIndex(void) @@ -42,72 +58,81 @@ static inline HvLpIndex HvLpConfig_getPrimaryLpIndex(void) static inline u64 HvLpConfig_getMsChunks(void) { - return HvCallCfg_getMsChunks(HvLpConfig_getLpIndex(), HvCallCfg_Cur); + return HvCall2(HvCallCfgGetMsChunks, HvLpConfig_getLpIndex(), + HvCallCfg_Cur); } static inline u64 HvLpConfig_getSystemPhysicalProcessors(void) { - return HvCallCfg_getSystemPhysicalProcessors(); + return HvCall0(HvCallCfgGetSystemPhysicalProcessors); } static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) { - return HvCallCfg_getNumProcsInSharedPool(sPI); + return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); } static inline u64 HvLpConfig_getPhysicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(), HvCallCfg_Cur); } static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void) { - return HvCallCfg_getSharedPoolIndex(HvLpConfig_getLpIndex()); + return HvCall1(HvCallCfgGetSharedPoolIndex, HvLpConfig_getLpIndex()); } static inline u64 HvLpConfig_getSharedProcUnits(void) { - return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), + return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(), HvCallCfg_Cur); } static inline u64 HvLpConfig_getMaxSharedProcUnits(void) { - return HvCallCfg_getSharedProcUnits(HvLpConfig_getLpIndex(), + return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(), HvCallCfg_Max); } static inline u64 HvLpConfig_getMaxPhysicalProcessors(void) { - return HvCallCfg_getPhysicalProcessors(HvLpConfig_getLpIndex(), + return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(), HvCallCfg_Max); } -static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) +static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp( + HvLpIndex lp) { - return HvCallCfg_getVirtualLanIndexMap(HvLpConfig_getLpIndex_outline()); + /* + * This is a new function in V5R1 so calls to this on older + * hypervisors will return -1 + */ + u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp); + if (retVal == -1) + retVal = 0; + return retVal; } -static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp( - HvLpIndex lp) +static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) { - return HvCallCfg_getVirtualLanIndexMap(lp); + return HvLpConfig_getVirtualLanIndexMapForLp( + HvLpConfig_getLpIndex_outline()); } static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, HvLpIndex lp2) { HvLpVirtualLanIndexMap virtualLanIndexMap1 = - HvCallCfg_getVirtualLanIndexMap(lp1); + HvLpConfig_getVirtualLanIndexMapForLp(lp1); HvLpVirtualLanIndexMap virtualLanIndexMap2 = - HvCallCfg_getVirtualLanIndexMap(lp2); + HvLpConfig_getVirtualLanIndexMapForLp(lp2); return ((virtualLanIndexMap1 & virtualLanIndexMap2) != 0); } static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp) { - return HvCallCfg_getHostingLpIndex(lp); + return HvCall1(HvCallCfgGetHostingLpIndex, lp); } #endif /* _HVLPCONFIG_H */ -- cgit v0.10.2 From c92877e0a079fe5a488cb244c7afb05137702b49 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:39 -0700 Subject: [PATCH] ppc64 iSeries: cleanup ItLpQueue.h Just white space cleaups and move process_iSeries_events into its only caller. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c index ff8a7db..bdf13b4 100644 --- a/arch/ppc64/kernel/idle.c +++ b/arch/ppc64/kernel/idle.c @@ -42,6 +42,11 @@ static int (*idle_loop)(void); static unsigned long maxYieldTime = 0; static unsigned long minYieldTime = 0xffffffffffffffffUL; +static inline void process_iSeries_events(void) +{ + asm volatile ("li 0,0x5555; sc" : : : "r0", "r3"); +} + static void yield_shared_processor(void) { unsigned long tb; diff --git a/include/asm-ppc64/iSeries/ItLpQueue.h b/include/asm-ppc64/iSeries/ItLpQueue.h index b2bdef4..393299e 100644 --- a/include/asm-ppc64/iSeries/ItLpQueue.h +++ b/include/asm-ppc64/iSeries/ItLpQueue.h @@ -64,9 +64,9 @@ struct ItLpQueue { u8 xPlicStatus; // 0x01 DedicatedIo or DedicatedLp or NotUsed u16 xSlicLogicalProcIndex; // 0x02 Logical Proc Index for correlation u8 xPlicRsvd[12]; // 0x04 - char* xSlicCurEventPtr; // 0x10 - char* xSlicLastValidEventPtr; // 0x18 - char* xSlicEventStackPtr; // 0x20 + char *xSlicCurEventPtr; // 0x10 + char *xSlicLastValidEventPtr; // 0x18 + char *xSlicEventStackPtr; // 0x20 u8 xIndex; // 0x28 unique sequential index. u8 xSlicRsvd[3]; // 0x29-2b u32 xInUseWord; // 0x2C @@ -76,17 +76,9 @@ struct ItLpQueue { extern struct ItLpQueue xItLpQueue; -extern struct HvLpEvent * ItLpQueue_getNextLpEvent(struct ItLpQueue *); +extern struct HvLpEvent *ItLpQueue_getNextLpEvent(struct ItLpQueue *); extern int ItLpQueue_isLpIntPending(struct ItLpQueue *); extern unsigned ItLpQueue_process(struct ItLpQueue *, struct pt_regs *); extern void ItLpQueue_clearValid(struct HvLpEvent *); -static __inline__ void process_iSeries_events(void) -{ - __asm__ __volatile__ ( - " li 0,0x5555 \n\ - sc" - : : : "r0", "r3"); -} - #endif /* _ITLPQUEUE_H */ -- cgit v0.10.2 From 4a5304f5ba04eff979cd108309eae7a00f3fff77 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:40 -0700 Subject: [PATCH] ppc64 iSeries: tidy up some includes and HvCall.h This patch removes some unused bits from HvCall.h and some unneeded #includes from other files. Also includes ItLpQueue.h in paca.h in preference to a stub declaration of struct ItLpQueue. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c index 0094ac7..abb9e5b 100644 --- a/arch/ppc64/kernel/asm-offsets.c +++ b/arch/ppc64/kernel/asm-offsets.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c index 9829cd4..1bff515 100644 --- a/arch/ppc64/kernel/iSeries_pci.c +++ b/arch/ppc64/kernel/iSeries_pci.c @@ -38,7 +38,6 @@ #include #include -#include #include #include #include diff --git a/arch/ppc64/kernel/mf.c b/arch/ppc64/kernel/mf.c index 5aca7e8..d98bebf 100644 --- a/arch/ppc64/kernel/mf.c +++ b/arch/ppc64/kernel/mf.c @@ -40,7 +40,6 @@ #include #include #include -#include #include /* diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c index 4cdafb4..de02aed 100644 --- a/arch/ppc64/kernel/rtc.c +++ b/arch/ppc64/kernel/rtc.c @@ -44,7 +44,6 @@ #include #include -#include extern int piranha_simulator; diff --git a/include/asm-ppc64/iSeries/HvCall.h b/include/asm-ppc64/iSeries/HvCall.h index c903387..c3f1947 100644 --- a/include/asm-ppc64/iSeries/HvCall.h +++ b/include/asm-ppc64/iSeries/HvCall.h @@ -27,48 +27,6 @@ #include #include -/* -enum HvCall_ReturnCode -{ - HvCall_Good = 0, - HvCall_Partial = 1, - HvCall_NotOwned = 2, - HvCall_NotFreed = 3, - HvCall_UnspecifiedError = 4 -}; - -enum HvCall_TypeOfSIT -{ - HvCall_ReduceOnly = 0, - HvCall_Unconditional = 1 -}; - -enum HvCall_TypeOfYield -{ - HvCall_YieldTimed = 0, // Yield until specified time - HvCall_YieldToActive = 1, // Yield until all active procs have run - HvCall_YieldToProc = 2 // Yield until the specified processor has run -}; - -enum HvCall_InterruptMasks -{ - HvCall_MaskIPI = 0x00000001, - HvCall_MaskLpEvent = 0x00000002, - HvCall_MaskLpProd = 0x00000004, - HvCall_MaskTimeout = 0x00000008 -}; - -enum HvCall_VaryOffChunkRc -{ - HvCall_VaryOffSucceeded = 0, - HvCall_VaryOffWithdrawn = 1, - HvCall_ChunkInLoadArea = 2, - HvCall_ChunkInHPT = 3, - HvCall_ChunkNotAccessible = 4, - HvCall_ChunkInUse = 5 -}; -*/ - /* Type of yield for HvCallBaseYieldProcessor */ #define HvCall_YieldTimed 0 /* Yield until specified time (tb) */ #define HvCall_YieldToActive 1 /* Yield until all active procs have run */ @@ -139,35 +97,12 @@ static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts) HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts); } -static inline void HvCall_clearLogBuffer(HvLpIndex lpindex) -{ - HvCall1(HvCallBaseClearLogBuffer, lpindex); -} - -static inline u32 HvCall_getLogBufferCodePage(HvLpIndex lpindex) -{ - u32 retVal = HvCall1(HvCallBaseGetLogBufferCodePage, lpindex); - return retVal; -} - -static inline int HvCall_getLogBufferFormat(HvLpIndex lpindex) -{ - int retVal = HvCall1(HvCallBaseGetLogBufferFormat, lpindex); - return retVal; -} - -static inline u32 HvCall_getLogBufferLength(HvLpIndex lpindex) -{ - u32 retVal = HvCall1(HvCallBaseGetLogBufferLength, lpindex); - return retVal; -} - -static inline void HvCall_setLogBufferFormatAndCodepage(int format, u32 codePage) +static inline void HvCall_setLogBufferFormatAndCodepage(int format, + u32 codePage) { HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage); } -extern int HvCall_readLogBuffer(HvLpIndex lpindex, void *buffer, u64 bufLen); extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen); static inline void HvCall_sendIPI(struct paca_struct *targetPaca) @@ -175,19 +110,4 @@ static inline void HvCall_sendIPI(struct paca_struct *targetPaca) HvCall1(HvCallBaseSendIPI, targetPaca->paca_index); } -static inline void HvCall_terminateMachineSrc(void) -{ - HvCall0(HvCallBaseTerminateMachineSrc); -} - -static inline void HvCall_setDABR(unsigned long val) -{ - HvCall1(HvCallCcSetDABR, val); -} - -static inline void HvCall_setDebugBus(unsigned long val) -{ - HvCall1(HvCallBaseSetDebugBus, val); -} - #endif /* _HVCALL_H */ diff --git a/include/asm-ppc64/paca.h b/include/asm-ppc64/paca.h index 1a0223b..ae76cae 100644 --- a/include/asm-ppc64/paca.h +++ b/include/asm-ppc64/paca.h @@ -20,13 +20,13 @@ #include #include #include +#include #include register struct paca_struct *local_paca asm("r13"); #define get_paca() local_paca struct task_struct; -struct ItLpQueue; /* * Defines the layout of the paca. -- cgit v0.10.2 From c670b1acd0ed0d9f7a27154759a9825cb5012ae4 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:41 -0700 Subject: [PATCH] ppc64 iSeries: misc header cleanups Last of this round of the iSeries header cleanups - don't have two defines for the same thing (HvMaxArchitectedLps and HvMaxArchitectedVirtualLans) - HvCallSc.h only needs linux/types.h - remove unused struct definition - add "extern" to some more function declarations Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/viopath.c b/arch/ppc64/kernel/viopath.c index ef52404..2a6c4f0 100644 --- a/arch/ppc64/kernel/viopath.c +++ b/arch/ppc64/kernel/viopath.c @@ -485,7 +485,7 @@ int viopath_open(HvLpIndex remoteLp, int subtype, int numReq) unsigned long flags; int tempNumAllocated; - if ((remoteLp >= HvMaxArchitectedLps) || (remoteLp == HvLpIndexInvalid)) + if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) return -EINVAL; subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; @@ -556,7 +556,7 @@ int viopath_close(HvLpIndex remoteLp, int subtype, int numReq) int numOpen; struct alloc_parms parms; - if ((remoteLp >= HvMaxArchitectedLps) || (remoteLp == HvLpIndexInvalid)) + if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) return -EINVAL; subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; diff --git a/include/asm-ppc64/iSeries/HvCallSc.h b/include/asm-ppc64/iSeries/HvCallSc.h index c32145f..a62cef3 100644 --- a/include/asm-ppc64/iSeries/HvCallSc.h +++ b/include/asm-ppc64/iSeries/HvCallSc.h @@ -19,7 +19,7 @@ #ifndef _HVCALLSC_H #define _HVCALLSC_H -#include +#include #define HvCallBase 0x8000000000000000ul #define HvCallCc 0x8001000000000000ul @@ -30,22 +30,22 @@ #define HvCallSm 0x8007000000000000ul #define HvCallXm 0x8009000000000000ul -u64 HvCall0(u64); -u64 HvCall1(u64, u64); -u64 HvCall2(u64, u64, u64); -u64 HvCall3(u64, u64, u64, u64); -u64 HvCall4(u64, u64, u64, u64, u64); -u64 HvCall5(u64, u64, u64, u64, u64, u64); -u64 HvCall6(u64, u64, u64, u64, u64, u64, u64); -u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64); +extern u64 HvCall0(u64); +extern u64 HvCall1(u64, u64); +extern u64 HvCall2(u64, u64, u64); +extern u64 HvCall3(u64, u64, u64, u64); +extern u64 HvCall4(u64, u64, u64, u64, u64); +extern u64 HvCall5(u64, u64, u64, u64, u64, u64); +extern u64 HvCall6(u64, u64, u64, u64, u64, u64, u64); +extern u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64); -u64 HvCall0Ret16(u64, void *); -u64 HvCall1Ret16(u64, void *, u64); -u64 HvCall2Ret16(u64, void *, u64, u64); -u64 HvCall3Ret16(u64, void *, u64, u64, u64); -u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64); -u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64); -u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64); -u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64); +extern u64 HvCall0Ret16(u64, void *); +extern u64 HvCall1Ret16(u64, void *, u64); +extern u64 HvCall2Ret16(u64, void *, u64, u64); +extern u64 HvCall3Ret16(u64, void *, u64, u64, u64); +extern u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64); +extern u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64); +extern u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64); +extern u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64); #endif /* _HVCALLSC_H */ diff --git a/include/asm-ppc64/iSeries/HvTypes.h b/include/asm-ppc64/iSeries/HvTypes.h index 111191d..b1ef2b4 100644 --- a/include/asm-ppc64/iSeries/HvTypes.h +++ b/include/asm-ppc64/iSeries/HvTypes.h @@ -40,14 +40,14 @@ typedef u64 HvIoToken; typedef u8 HvLpName[8]; typedef u32 HvIoId; typedef u64 HvRealMemoryIndex; -typedef u32 HvLpIndexMap; /* Must hold HvMaxArchitectedLps bits!!! */ +typedef u32 HvLpIndexMap; /* Must hold HVMAXARCHITECTEDLPS bits!!! */ typedef u16 HvLpVrmIndex; typedef u32 HvXmGenerationId; typedef u8 HvLpBusPool; typedef u8 HvLpSharedPoolIndex; typedef u16 HvLpSharedProcUnitsX100; typedef u8 HvLpVirtualLanIndex; -typedef u16 HvLpVirtualLanIndexMap; /* Must hold HvMaxArchitectedVirtualLans bits!!! */ +typedef u16 HvLpVirtualLanIndexMap; /* Must hold HVMAXARCHITECTEDVIRTUALLANS bits!!! */ typedef u16 HvBusNumber; /* Hypervisor Bus Number */ typedef u8 HvSubBusNumber; /* Hypervisor SubBus Number */ typedef u8 HvAgentId; /* Hypervisor DevFn */ @@ -66,15 +66,13 @@ typedef u8 HvAgentId; /* Hypervisor DevFn */ #define HVPAGESPERMEG 256 #define HVPAGESPERCHUNK 64 -#define HvMaxArchitectedLps ((HvLpIndex)HVMAXARCHITECTEDLPS) -#define HvMaxArchitectedVirtualLans ((HvLpVirtualLanIndex)16) #define HvLpIndexInvalid ((HvLpIndex)0xff) /* * Enums for the sub-components under PLIC * Used in HvCall and HvPrimaryCall */ -enum HvCallCompIds { +enum { HvCallCompId = 0, HvCallCpuCtlsCompId = 1, HvCallCfgCompId = 2, diff --git a/include/asm-ppc64/iSeries/ItVpdAreas.h b/include/asm-ppc64/iSeries/ItVpdAreas.h index 97cfa6c..71b3ad2 100644 --- a/include/asm-ppc64/iSeries/ItVpdAreas.h +++ b/include/asm-ppc64/iSeries/ItVpdAreas.h @@ -61,12 +61,6 @@ #define ItVpdAreasMaxSlotLabels 192 -struct SlicVpdAdrs { - u32 pad1; - void *vpdAddr; -}; - - struct ItVpdAreas { u32 xSlicDesc; // Descriptor 000-003 u16 xSlicSize; // Size of this control block 004-005 -- cgit v0.10.2 From ea7190d0afebbd922eeb13ee6a8148b17964b1b2 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:42 -0700 Subject: [PATCH] ppc64 iSeries: remove iSeries_pci_reset.c The file arch/ppc64/kernel/iSeries_pci_reset contains only one function that is not use anywhere (any more). Remove it. This function is the only user of the ReturnCode member of iSeries_Device_Node, so remove that as well. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 96d90b0..9132d92 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -16,7 +16,7 @@ obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o -pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_pci_reset.o +pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) diff --git a/arch/ppc64/kernel/iSeries_pci_reset.c b/arch/ppc64/kernel/iSeries_pci_reset.c deleted file mode 100644 index 0f785e4..0000000 --- a/arch/ppc64/kernel/iSeries_pci_reset.c +++ /dev/null @@ -1,104 +0,0 @@ -#define PCIFR(...) -/************************************************************************/ -/* File iSeries_pci_reset.c created by Allan Trautman on Mar 21 2001. */ -/************************************************************************/ -/* This code supports the pci interface on the IBM iSeries systems. */ -/* Copyright (C) 20yy */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that 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., */ -/* 59 Temple Place, Suite 330, */ -/* Boston, MA 02111-1307 USA */ -/************************************************************************/ -/* Change Activity: */ -/* Created, March 20, 2001 */ -/* April 30, 2001, Added return codes on functions. */ -/* September 10, 2001, Ported to ppc64. */ -/* End Change Activity */ -/************************************************************************/ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include "pci.h" - -/* - * Interface to toggle the reset line - * Time is in .1 seconds, need for seconds. - */ -int iSeries_Device_ToggleReset(struct pci_dev *PciDev, int AssertTime, - int DelayTime) -{ - unsigned int AssertDelay, WaitDelay; - struct iSeries_Device_Node *DeviceNode = - (struct iSeries_Device_Node *)PciDev->sysdata; - - if (DeviceNode == NULL) { - printk("PCI: Pci Reset Failed, Device Node not found for pci_dev %p\n", - PciDev); - return -1; - } - /* - * Set defaults, Assert is .5 second, Wait is 3 seconds. - */ - if (AssertTime == 0) - AssertDelay = 500; - else - AssertDelay = AssertTime * 100; - - if (DelayTime == 0) - WaitDelay = 3000; - else - WaitDelay = DelayTime * 100; - - /* - * Assert reset - */ - DeviceNode->ReturnCode = HvCallPci_setSlotReset(ISERIES_BUS(DeviceNode), - 0x00, DeviceNode->AgentId, 1); - if (DeviceNode->ReturnCode == 0) { - msleep(AssertDelay); /* Sleep for the time */ - DeviceNode->ReturnCode = - HvCallPci_setSlotReset(ISERIES_BUS(DeviceNode), - 0x00, DeviceNode->AgentId, 0); - - /* - * Wait for device to reset - */ - msleep(WaitDelay); - } - if (DeviceNode->ReturnCode == 0) - PCIFR("Slot 0x%04X.%02 Reset\n", ISERIES_BUS(DeviceNode), - DeviceNode->AgentId); - else { - printk("PCI: Slot 0x%04X.%02X Reset Failed, RCode: %04X\n", - ISERIES_BUS(DeviceNode), DeviceNode->AgentId, - DeviceNode->ReturnCode); - PCIFR("Slot 0x%04X.%02X Reset Failed, RCode: %04X\n", - ISERIES_BUS(DeviceNode), DeviceNode->AgentId, - DeviceNode->ReturnCode); - } - return DeviceNode->ReturnCode; -} -EXPORT_SYMBOL(iSeries_Device_ToggleReset); diff --git a/include/asm-ppc64/iSeries/iSeries_pci.h b/include/asm-ppc64/iSeries/iSeries_pci.h index f45cd8a..4313a66 100644 --- a/include/asm-ppc64/iSeries/iSeries_pci.h +++ b/include/asm-ppc64/iSeries/iSeries_pci.h @@ -92,7 +92,6 @@ struct iSeries_Device_Node { int DevFn; /* Linux devfn */ int BarOffset; int Irq; /* Assigned IRQ */ - int ReturnCode; /* Return Code Holder */ int IoRetry; /* Current Retry Count */ int Flags; /* Possible flags(disable/bist)*/ u16 Vendor; /* Vendor ID */ @@ -107,7 +106,5 @@ struct iSeries_Device_Node { extern int iSeries_Device_Information(struct pci_dev*, char*, int); extern void iSeries_Get_Location_Code(struct iSeries_Device_Node*); -extern int iSeries_Device_ToggleReset(struct pci_dev* PciDev, - int AssertTime, int DelayTime); #endif /* _ISERIES_64_PCI_H */ -- cgit v0.10.2 From e7eb22d201936fb3450fa5d1d30cbf2de2fb918b Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:44 -0700 Subject: [PATCH] ppc64 iSeries: iommu.h cleanups The iommu_table_cb structure is iSeries specific, so move it to the header file that declares the function we pass it to. vio_tce_table and iommu_setup_iSeries no longer exist, so remove their declarations. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-ppc64/iSeries/HvCallXm.h b/include/asm-ppc64/iSeries/HvCallXm.h index 1362a42..8b9ba60 100644 --- a/include/asm-ppc64/iSeries/HvCallXm.h +++ b/include/asm-ppc64/iSeries/HvCallXm.h @@ -16,6 +16,23 @@ #define HvCallXmSetTce HvCallXm + 11 #define HvCallXmSetTces HvCallXm + 13 +/* + * Structure passed to HvCallXm_getTceTableParms + */ +struct iommu_table_cb { + unsigned long itc_busno; /* Bus number for this tce table */ + unsigned long itc_start; /* Will be NULL for secondary */ + unsigned long itc_totalsize; /* Size (in pages) of whole table */ + unsigned long itc_offset; /* Index into real tce table of the + start of our section */ + unsigned long itc_size; /* Size (in pages) of our section */ + unsigned long itc_index; /* Index of this tce table */ + unsigned short itc_maxtables; /* Max num of tables for partition */ + unsigned char itc_virtbus; /* Flag to indicate virtual bus */ + unsigned char itc_slotno; /* IOA Tce Slot Index */ + unsigned char itc_rsvd[4]; +}; + static inline void HvCallXm_getTceTableParms(u64 cb) { HvCall1(HvCallXmGetTceTableParms, cb); diff --git a/include/asm-ppc64/iommu.h b/include/asm-ppc64/iommu.h index bd53ca4..d9b5337 100644 --- a/include/asm-ppc64/iommu.h +++ b/include/asm-ppc64/iommu.h @@ -82,24 +82,6 @@ struct iommu_table { unsigned long *it_map; /* A simple allocation bitmap for now */ }; -#ifdef CONFIG_PPC_ISERIES -struct iommu_table_cb { - unsigned long itc_busno; /* Bus number for this tce table */ - unsigned long itc_start; /* Will be NULL for secondary */ - unsigned long itc_totalsize; /* Size (in pages) of whole table */ - unsigned long itc_offset; /* Index into real tce table of the - start of our section */ - unsigned long itc_size; /* Size (in pages) of our section */ - unsigned long itc_index; /* Index of this tce table */ - unsigned short itc_maxtables; /* Max num of tables for partition */ - unsigned char itc_virtbus; /* Flag to indicate virtual bus */ - unsigned char itc_slotno; /* IOA Tce Slot Index */ - unsigned char itc_rsvd[4]; -}; - -extern struct iommu_table vio_tce_table; /* Tce table for virtual bus */ -#endif /* CONFIG_PPC_ISERIES */ - struct scatterlist; #ifdef CONFIG_PPC_MULTIPLATFORM @@ -122,9 +104,6 @@ extern void iommu_devnode_init_pSeries(struct device_node *dn); #ifdef CONFIG_PPC_ISERIES -/* Walks all buses and creates iommu tables */ -extern void iommu_setup_iSeries(void); - /* Initializes tables for bio buses */ extern void __init iommu_vio_init(void); -- cgit v0.10.2 From 57ca86d4f0e44f81be10bc77a5d0e26760e4844f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:45 -0700 Subject: [PATCH] ppc64 iSeries: iSeries_VpdInfo.c cleanups Clean up iSeries_VpdInfo.c: - white space and comment fixes - make a function static - the functions here are only called from iSeries_pci.c, so CONFIG_PCI will be set (so remove check) - only build when CONFIG_PCI is set - remove unneeded includes and cast Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 9132d92..ada9be8 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -16,13 +16,12 @@ obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o -pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o +pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_VpdInfo.o pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ - iSeries_VpdInfo.o XmPciLpEvent.o \ +obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o XmPciLpEvent.o \ HvCall.o HvLpConfig.o LparData.o \ iSeries_setup.o ItLpQueue.o hvCall.o \ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ diff --git a/arch/ppc64/kernel/iSeries_VpdInfo.c b/arch/ppc64/kernel/iSeries_VpdInfo.c index a82caf9..9c89ce9 100644 --- a/arch/ppc64/kernel/iSeries_VpdInfo.c +++ b/arch/ppc64/kernel/iSeries_VpdInfo.c @@ -1,31 +1,31 @@ -/************************************************************************/ -/* File iSeries_vpdInfo.c created by Allan Trautman on Fri Feb 2 2001. */ -/************************************************************************/ -/* This code gets the card location of the hardware */ -/* Copyright (C) 20yy */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that 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., */ -/* 59 Temple Place, Suite 330, */ -/* Boston, MA 02111-1307 USA */ -/************************************************************************/ -/* Change Activity: */ -/* Created, Feb 2, 2001 */ -/* Ported to ppc64, August 20, 2001 */ -/* End Change Activity */ -/************************************************************************/ -#include +/* + * File iSeries_vpdInfo.c created by Allan Trautman on Fri Feb 2 2001. + * + * This code gets the card location of the hardware + * Copyright (C) 2001 + * Copyright (C) 2005 Stephen Rothwel, IBM Corp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * Change Activity: + * Created, Feb 2, 2001 + * Ported to ppc64, August 20, 2001 + * End Change Activity + */ #include #include #include @@ -34,14 +34,13 @@ #include #include -#include #include -#include "pci.h" /* * Size of Bus VPD data */ #define BUS_VPDSIZE 1024 + /* * Bus Vpd Tags */ @@ -49,6 +48,7 @@ #define VpdEndOfAreaTag 0x79 #define VpdIdStringTag 0x82 #define VpdVendorAreaTag 0x84 + /* * Mfg Area Tags */ @@ -78,7 +78,7 @@ struct SlotMapStruct { char CardLocation[3]; char Parms[8]; char Reserved[2]; -}; +}; typedef struct SlotMapStruct SlotMap; #define SLOT_ENTRY_SIZE 16 @@ -111,28 +111,26 @@ int iSeries_Device_Information(struct pci_dev *PciDev, char *buffer, PciDev->vendor); len += sprintf(buffer + len, "Frame%3d, Card %4s ", DevNode->FrameId, DevNode->CardLocation); -#ifdef CONFIG_PCI if (pci_class_name(PciDev->class >> 8) == 0) len += sprintf(buffer + len, "0x%04X ", (int)(PciDev->class >> 8)); else len += sprintf(buffer + len, "%s", pci_class_name(PciDev->class >> 8)); -#endif return len; } /* * Parse the Slot Area */ -void iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen, +static void iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen, struct iSeries_Device_Node *DevNode) { int SlotMapLen = MapLen; SlotMap *SlotMapPtr = MapPtr; /* - * Parse Slot label until we find the one requrested + * Parse Slot label until we find the one requested */ while (SlotMapLen > 0) { if (SlotMapPtr->AgentId == DevNode->AgentId ) { @@ -182,7 +180,7 @@ static void iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen, if (SlotMapFmt == 0x1004) SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr + MFG_ENTRY_SIZE + 1); - else + else SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr + MFG_ENTRY_SIZE); iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen, DevNode); @@ -193,8 +191,8 @@ static void iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen, */ MfgAreaPtr = (MfgArea *)((char *)MfgAreaPtr + MfgTagLen + MFG_ENTRY_SIZE); - MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE); - } + MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE); + } } /* @@ -205,7 +203,7 @@ static int iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength) { u8 *PhbPtr = AreaPtr; int DataLen = AreaLength; - char PhbId = 0xFF; + char PhbId = 0xFF; while (DataLen > 0) { if ((*PhbPtr == 'B') && (*(PhbPtr + 1) == 'U') @@ -215,7 +213,7 @@ static int iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength) ++PhbPtr; PhbId = (*PhbPtr & 0x0F); break; - } + } ++PhbPtr; --DataLen; } @@ -232,7 +230,7 @@ static void iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen, int DataLen = VpdDataLen - 3; while ((*TagPtr != VpdEndOfAreaTag) && (DataLen > 0)) { - int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256); + int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256); u8 *AreaData = TagPtr + 3; if (*TagPtr == VpdIdStringTag) @@ -243,12 +241,12 @@ static void iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen, TagPtr = AreaData + AreaLen; DataLen -= AreaLen; } -} +} void iSeries_Get_Location_Code(struct iSeries_Device_Node *DevNode) { int BusVpdLen = 0; - u8 *BusVpdPtr = (u8 *)kmalloc(BUS_VPDSIZE, GFP_KERNEL); + u8 *BusVpdPtr = kmalloc(BUS_VPDSIZE, GFP_KERNEL); if (BusVpdPtr == NULL) { printk("PCI: Bus VPD Buffer allocation failure.\n"); -- cgit v0.10.2 From aab41dea80b1b00e66533af096f797320be05f13 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:46 -0700 Subject: [PATCH] ppc64 iSeries: iSeries_pci.h cleanups Remove no longer used things from iSeries_pci.h. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c index 1bff515..1313a7a 100644 --- a/arch/ppc64/kernel/iSeries_pci.c +++ b/arch/ppc64/kernel/iSeries_pci.c @@ -497,7 +497,6 @@ static int scan_bridge_slot(HvBusNumber Bus, ++DeviceCount; node = build_device_node(Bus, SubBus, EADsIdSel, Function); - node->Vendor = VendorId; node->Irq = Irq; node->LogicalSlot = BridgeInfo->logicalSlotNumber; diff --git a/include/asm-ppc64/iSeries/iSeries_pci.h b/include/asm-ppc64/iSeries/iSeries_pci.h index 4313a66..5d127cf 100644 --- a/include/asm-ppc64/iSeries/iSeries_pci.h +++ b/include/asm-ppc64/iSeries/iSeries_pci.h @@ -44,8 +44,7 @@ struct iSeries_Device_Node; #define ISERIES_SUBBUS(DevPtr) DevPtr->DsaAddr.Dsa.subBusNumber #define ISERIES_DEVICE(DevPtr) DevPtr->DsaAddr.Dsa.deviceId #define ISERIES_DSA(DevPtr) DevPtr->DsaAddr.DsaAddr -#define ISERIES_DEVFUN(DevPtr) DevPtr->DevFn -#define ISERIES_DEVNODE(PciDev) ((struct iSeries_Device_Node*)PciDev->sysdata) +#define ISERIES_DEVNODE(PciDev) ((struct iSeries_Device_Node *)PciDev->sysdata) #define EADsMaxAgents 7 @@ -63,17 +62,6 @@ struct iSeries_Device_Node; #define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) /* - * N.B. the ISERIES_DECODE_* macros are not used anywhere, and I think - * the 0x71 (at least) must be wrong - 0x78 maybe? -- paulus. - */ -#define ISERIES_DECODE_DEVFN(linuxdevfn) \ - (((linuxdevfn & 0x71) << 1) | (linuxdevfn & 0x07)) -#define ISERIES_DECODE_DEVICE(linuxdevfn) \ - (((linuxdevfn & 0x38) >> 3) | (((linuxdevfn & 0x40) >> 2) + 0x10)) -#define ISERIES_DECODE_FUNCTION(linuxdevfn) \ - (linuxdevfn & 0x07) - -/* * Converts Virtual Address to Real Address for Hypervisor calls */ #define ISERIES_HV_ADDR(virtaddr) \ @@ -90,15 +78,12 @@ struct iSeries_Device_Node { /* deviceId, barNumber */ HvAgentId AgentId; /* Hypervisor DevFn */ int DevFn; /* Linux devfn */ - int BarOffset; int Irq; /* Assigned IRQ */ int IoRetry; /* Current Retry Count */ int Flags; /* Possible flags(disable/bist)*/ - u16 Vendor; /* Vendor ID */ u8 LogicalSlot; /* Hv Slot Index for Tces */ struct iommu_table *iommu_table;/* Device TCE Table */ u8 PhbId; /* Phb Card is on. */ - u16 Board; /* Board Number */ u8 FrameId; /* iSeries spcn Frame Id */ char CardLocation[4];/* Char format of planar vpd */ char Location[20]; /* Frame 1, Card C10 */ -- cgit v0.10.2 From a2ebaf250fabc5c5644b707dbee44c9e0ec442e9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:47 -0700 Subject: [PATCH] ppc64 iSeries: remove IoRetry from iSeries_Device_Node The IoRetry member of iSeries_Devide_Node is really only used locally, so remove it and replace it with a local variable. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c index 1313a7a..0a28b6c 100644 --- a/arch/ppc64/kernel/iSeries_pci.c +++ b/arch/ppc64/kernel/iSeries_pci.c @@ -225,7 +225,6 @@ static struct iSeries_Device_Node *build_device_node(HvBusNumber Bus, node->DsaAddr.Dsa.deviceId = 0x10; node->AgentId = AgentId; node->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function); - node->IoRetry = 0; iSeries_Get_Location_Code(node); return node; } @@ -658,38 +657,34 @@ static struct pci_ops iSeries_pci_ops = { * Check Return Code * -> On Failure, print and log information. * Increment Retry Count, if exceeds max, panic partition. - * -> If in retry, print and log success * * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234 * PCI: Device 23.90 ReadL Retry( 1) * PCI: Device 23.90 ReadL Retry Successful(1) */ static int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode, - u64 ret) + int *retry, u64 ret) { if (ret != 0) { ++Pci_Error_Count; - ++DevNode->IoRetry; + (*retry)++; printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", TextHdr, DevNode->DsaAddr.Dsa.busNumber, DevNode->DevFn, - DevNode->IoRetry, (int)ret); + *retry, (int)ret); /* * Bump the retry and check for retry count exceeded. * If, Exceeded, panic the system. */ - if ((DevNode->IoRetry > Pci_Retry_Max) && + if (((*retry) > Pci_Retry_Max) && (Pci_Error_Flag > 0)) { mf_display_src(0xB6000103); - panic_timeout = 0; + panic_timeout = 0; panic("PCI: Hardware I/O Error, SRC B6000103, " "Automatic Reboot Disabled.\n"); } return -1; /* Retry Try */ } - /* If retry was in progress, log success and rest retry count */ - if (DevNode->IoRetry > 0) - DevNode->IoRetry = 0; - return 0; + return 0; } /* @@ -735,6 +730,7 @@ u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; + int retry = 0; struct HvCallPci_LoadReturn ret; struct iSeries_Device_Node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); @@ -754,7 +750,7 @@ u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress) do { ++Pci_Io_Read_Count; HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0); - } while (CheckReturnCode("RDB", DevNode, ret.rc) != 0); + } while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0); return (u8)ret.value; } @@ -764,6 +760,7 @@ u16 iSeries_Read_Word(const volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; + int retry = 0; struct HvCallPci_LoadReturn ret; struct iSeries_Device_Node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); @@ -784,7 +781,7 @@ u16 iSeries_Read_Word(const volatile void __iomem *IoAddress) ++Pci_Io_Read_Count; HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa, BarOffset, 0); - } while (CheckReturnCode("RDW", DevNode, ret.rc) != 0); + } while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0); return swab16((u16)ret.value); } @@ -794,6 +791,7 @@ u32 iSeries_Read_Long(const volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; + int retry = 0; struct HvCallPci_LoadReturn ret; struct iSeries_Device_Node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); @@ -814,7 +812,7 @@ u32 iSeries_Read_Long(const volatile void __iomem *IoAddress) ++Pci_Io_Read_Count; HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa, BarOffset, 0); - } while (CheckReturnCode("RDL", DevNode, ret.rc) != 0); + } while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0); return swab32((u32)ret.value); } @@ -831,6 +829,7 @@ void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; + int retry = 0; u64 rc; struct iSeries_Device_Node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); @@ -850,7 +849,7 @@ void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress) do { ++Pci_Io_Write_Count; rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0); - } while (CheckReturnCode("WWB", DevNode, rc) != 0); + } while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0); } EXPORT_SYMBOL(iSeries_Write_Byte); @@ -858,6 +857,7 @@ void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; + int retry = 0; u64 rc; struct iSeries_Device_Node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); @@ -877,7 +877,7 @@ void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress) do { ++Pci_Io_Write_Count; rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0); - } while (CheckReturnCode("WWW", DevNode, rc) != 0); + } while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0); } EXPORT_SYMBOL(iSeries_Write_Word); @@ -885,6 +885,7 @@ void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress) { u64 BarOffset; u64 dsa; + int retry = 0; u64 rc; struct iSeries_Device_Node *DevNode = xlate_iomm_address(IoAddress, &dsa, &BarOffset); @@ -904,6 +905,6 @@ void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress) do { ++Pci_Io_Write_Count; rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0); - } while (CheckReturnCode("WWL", DevNode, rc) != 0); + } while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0); } EXPORT_SYMBOL(iSeries_Write_Long); diff --git a/include/asm-ppc64/iSeries/iSeries_pci.h b/include/asm-ppc64/iSeries/iSeries_pci.h index 5d127cf..ee0212f 100644 --- a/include/asm-ppc64/iSeries/iSeries_pci.h +++ b/include/asm-ppc64/iSeries/iSeries_pci.h @@ -79,7 +79,6 @@ struct iSeries_Device_Node { HvAgentId AgentId; /* Hypervisor DevFn */ int DevFn; /* Linux devfn */ int Irq; /* Assigned IRQ */ - int IoRetry; /* Current Retry Count */ int Flags; /* Possible flags(disable/bist)*/ u8 LogicalSlot; /* Hv Slot Index for Tces */ struct iommu_table *iommu_table;/* Device TCE Table */ -- cgit v0.10.2 From 061c063efce96b33f9e26d5f83a8eb0643fa493c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:48 -0700 Subject: [PATCH] ppc64 iSeries: remove some more members of iSeries_Device_Node The AgentId, PhbId, FrameId, CardLocation and Location members of iSeries_Device_Node are stored early in the boot process just so that a message about the device can be printed later in the boot process. Remove them and construct the message by doing the VPD parsing at the time the message is printed. Also remove a few unused defines in iSeries_VpdInfo.c. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/iSeries_VpdInfo.c b/arch/ppc64/kernel/iSeries_VpdInfo.c index 9c89ce9..d11c732 100644 --- a/arch/ppc64/kernel/iSeries_VpdInfo.c +++ b/arch/ppc64/kernel/iSeries_VpdInfo.c @@ -44,7 +44,6 @@ /* * Bus Vpd Tags */ -#define VpdEndOfDataTag 0x78 #define VpdEndOfAreaTag 0x79 #define VpdIdStringTag 0x82 #define VpdVendorAreaTag 0x84 @@ -52,11 +51,8 @@ /* * Mfg Area Tags */ -#define VpdFruFlag 0x4647 // "FG" #define VpdFruFrameId 0x4649 // "FI" #define VpdSlotMapFormat 0x4D46 // "MF" -#define VpdAsmPartNumber 0x504E // "PN" -#define VpdFruSerial 0x534E // "SN" #define VpdSlotMap 0x534D // "SM" /* @@ -83,48 +79,10 @@ typedef struct SlotMapStruct SlotMap; #define SLOT_ENTRY_SIZE 16 /* - * Formats the device information. - * - Pass in pci_dev* pointer to the device. - * - Pass in buffer to place the data. Danger here is the buffer must - * be as big as the client says it is. Should be at least 128 bytes. - * Return will the length of the string data put in the buffer. - * Format: - * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet - * controller - */ -int iSeries_Device_Information(struct pci_dev *PciDev, char *buffer, - int BufferSize) -{ - struct iSeries_Device_Node *DevNode = - (struct iSeries_Device_Node *)PciDev->sysdata; - int len; - - if (DevNode == NULL) - return sprintf(buffer, - "PCI: iSeries_Device_Information DevNode is NULL"); - - if (BufferSize < 128) - return 0; - - len = sprintf(buffer, "PCI: Bus%3d, Device%3d, Vendor %04X ", - ISERIES_BUS(DevNode), PCI_SLOT(PciDev->devfn), - PciDev->vendor); - len += sprintf(buffer + len, "Frame%3d, Card %4s ", - DevNode->FrameId, DevNode->CardLocation); - if (pci_class_name(PciDev->class >> 8) == 0) - len += sprintf(buffer + len, "0x%04X ", - (int)(PciDev->class >> 8)); - else - len += sprintf(buffer + len, "%s", - pci_class_name(PciDev->class >> 8)); - return len; -} - -/* * Parse the Slot Area */ -static void iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen, - struct iSeries_Device_Node *DevNode) +static void __init iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen, + HvAgentId agent, u8 *PhbId, char card[4]) { int SlotMapLen = MapLen; SlotMap *SlotMapPtr = MapPtr; @@ -133,17 +91,16 @@ static void iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen, * Parse Slot label until we find the one requested */ while (SlotMapLen > 0) { - if (SlotMapPtr->AgentId == DevNode->AgentId ) { + if (SlotMapPtr->AgentId == agent) { /* * If Phb wasn't found, grab the entry first one found. */ - if (DevNode->PhbId == 0xff) - DevNode->PhbId = SlotMapPtr->PhbId; + if (*PhbId == 0xff) + *PhbId = SlotMapPtr->PhbId; /* Found it, extract the data. */ - if (SlotMapPtr->PhbId == DevNode->PhbId ) { - memcpy(&DevNode->CardLocation, - &SlotMapPtr->CardLocation, 3); - DevNode->CardLocation[3] = 0; + if (SlotMapPtr->PhbId == *PhbId) { + memcpy(card, &SlotMapPtr->CardLocation, 3); + card[3] = 0; break; } } @@ -156,8 +113,9 @@ static void iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen, /* * Parse the Mfg Area */ -static void iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen, - struct iSeries_Device_Node *DevNode) +static void __init iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen, + HvAgentId agent, u8 *PhbId, + u8 *frame, char card[4]) { MfgArea *MfgAreaPtr = (MfgArea *)AreaData; int MfgAreaLen = AreaLen; @@ -168,7 +126,7 @@ static void iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen, int MfgTagLen = MfgAreaPtr->TagLength; /* Frame ID (FI 4649020310 ) */ if (MfgAreaPtr->Tag == VpdFruFrameId) /* FI */ - DevNode->FrameId = MfgAreaPtr->AreaData1; + *frame = MfgAreaPtr->AreaData1; /* Slot Map Format (MF 4D46020004 ) */ else if (MfgAreaPtr->Tag == VpdSlotMapFormat) /* MF */ SlotMapFmt = (MfgAreaPtr->AreaData1 * 256) @@ -183,7 +141,8 @@ static void iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen, else SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr + MFG_ENTRY_SIZE); - iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen, DevNode); + iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen, + agent, PhbId, card); } /* * Point to the next Mfg Area @@ -199,7 +158,7 @@ static void iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen, * Look for "BUS".. Data is not Null terminated. * PHBID of 0xFF indicates PHB was not found in VPD Data. */ -static int iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength) +static int __init iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength) { u8 *PhbPtr = AreaPtr; int DataLen = AreaLength; @@ -223,27 +182,30 @@ static int iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength) /* * Parse out the VPD Areas */ -static void iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen, - struct iSeries_Device_Node *DevNode) +static void __init iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen, + HvAgentId agent, u8 *frame, char card[4]) { u8 *TagPtr = VpdData; int DataLen = VpdDataLen - 3; + u8 PhbId; while ((*TagPtr != VpdEndOfAreaTag) && (DataLen > 0)) { int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256); u8 *AreaData = TagPtr + 3; if (*TagPtr == VpdIdStringTag) - DevNode->PhbId = iSeries_Parse_PhbId(AreaData, AreaLen); + PhbId = iSeries_Parse_PhbId(AreaData, AreaLen); else if (*TagPtr == VpdVendorAreaTag) - iSeries_Parse_MfgArea(AreaData, AreaLen, DevNode); + iSeries_Parse_MfgArea(AreaData, AreaLen, + agent, &PhbId, frame, card); /* Point to next Area. */ TagPtr = AreaData + AreaLen; DataLen -= AreaLen; } } -void iSeries_Get_Location_Code(struct iSeries_Device_Node *DevNode) +static void __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent, + u8 *frame, char card[4]) { int BusVpdLen = 0; u8 *BusVpdPtr = kmalloc(BUS_VPDSIZE, GFP_KERNEL); @@ -252,23 +214,58 @@ void iSeries_Get_Location_Code(struct iSeries_Device_Node *DevNode) printk("PCI: Bus VPD Buffer allocation failure.\n"); return; } - BusVpdLen = HvCallPci_getBusVpd(ISERIES_BUS(DevNode), - ISERIES_HV_ADDR(BusVpdPtr), + BusVpdLen = HvCallPci_getBusVpd(bus, ISERIES_HV_ADDR(BusVpdPtr), BUS_VPDSIZE); if (BusVpdLen == 0) { - kfree(BusVpdPtr); printk("PCI: Bus VPD Buffer zero length.\n"); - return; + goto out_free; } /* printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen); */ /* Make sure this is what I think it is */ if (*BusVpdPtr != VpdIdStringTag) { /* 0x82 */ printk("PCI: Bus VPD Buffer missing starting tag.\n"); - kfree(BusVpdPtr); - return; + goto out_free; } - iSeries_Parse_Vpd(BusVpdPtr,BusVpdLen, DevNode); - sprintf(DevNode->Location, "Frame%3d, Card %-4s", DevNode->FrameId, - DevNode->CardLocation); + iSeries_Parse_Vpd(BusVpdPtr, BusVpdLen, agent, frame, card); +out_free: kfree(BusVpdPtr); } + +/* + * Prints the device information. + * - Pass in pci_dev* pointer to the device. + * - Pass in the device count + * + * Format: + * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet + * controller + */ +void __init iSeries_Device_Information(struct pci_dev *PciDev, int count) +{ + struct iSeries_Device_Node *DevNode = PciDev->sysdata; + u16 bus; + u8 frame; + char card[4]; + HvSubBusNumber subbus; + HvAgentId agent; + + if (DevNode == NULL) { + printk("%d. PCI: iSeries_Device_Information DevNode is NULL\n", + count); + return; + } + + bus = ISERIES_BUS(DevNode); + subbus = ISERIES_SUBBUS(DevNode); + agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus), + ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); + iSeries_Get_Location_Code(bus, agent, &frame, card); + + printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, Card %4s ", + count, bus, PCI_SLOT(PciDev->devfn), PciDev->vendor, + frame, card); + if (pci_class_name(PciDev->class >> 8) == 0) + printk("0x%04X\n", (int)(PciDev->class >> 8)); + else + printk("%s\n", pci_class_name(PciDev->class >> 8)); +} diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c index 0a28b6c..356e4fd 100644 --- a/arch/ppc64/kernel/iSeries_pci.c +++ b/arch/ppc64/kernel/iSeries_pci.c @@ -223,9 +223,7 @@ static struct iSeries_Device_Node *build_device_node(HvBusNumber Bus, node->DsaAddr.Dsa.busNumber = Bus; node->DsaAddr.Dsa.subBusNumber = SubBus; node->DsaAddr.Dsa.deviceId = 0x10; - node->AgentId = AgentId; node->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function); - iSeries_Get_Location_Code(node); return node; } @@ -299,7 +297,6 @@ void __init iSeries_pci_final_fixup(void) { struct pci_dev *pdev = NULL; struct iSeries_Device_Node *node; - char Buffer[256]; int DeviceCount = 0; PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n"); @@ -321,9 +318,7 @@ void __init iSeries_pci_final_fixup(void) "pdev 0x%p <==> DevNode 0x%p\n", pdev, node); allocate_device_bars(pdev); - iSeries_Device_Information(pdev, Buffer, - sizeof(Buffer)); - printk("%d. %s\n", DeviceCount, Buffer); + iSeries_Device_Information(pdev, DeviceCount); iommu_devnode_init_iSeries(node); } else printk("PCI: Device Tree not found for 0x%016lX\n", diff --git a/include/asm-ppc64/iSeries/iSeries_pci.h b/include/asm-ppc64/iSeries/iSeries_pci.h index ee0212f..575f611 100644 --- a/include/asm-ppc64/iSeries/iSeries_pci.h +++ b/include/asm-ppc64/iSeries/iSeries_pci.h @@ -76,19 +76,13 @@ struct iSeries_Device_Node { union HvDsaMap DsaAddr; /* Direct Select Address */ /* busNumber, subBusNumber, */ /* deviceId, barNumber */ - HvAgentId AgentId; /* Hypervisor DevFn */ int DevFn; /* Linux devfn */ int Irq; /* Assigned IRQ */ int Flags; /* Possible flags(disable/bist)*/ u8 LogicalSlot; /* Hv Slot Index for Tces */ struct iommu_table *iommu_table;/* Device TCE Table */ - u8 PhbId; /* Phb Card is on. */ - u8 FrameId; /* iSeries spcn Frame Id */ - char CardLocation[4];/* Char format of planar vpd */ - char Location[20]; /* Frame 1, Card C10 */ }; -extern int iSeries_Device_Information(struct pci_dev*, char*, int); -extern void iSeries_Get_Location_Code(struct iSeries_Device_Node*); +extern void iSeries_Device_Information(struct pci_dev*, int); #endif /* _ISERIES_64_PCI_H */ -- cgit v0.10.2 From 0c3b4f1a8e06584d8a1051a74ed79cf8b41f703e Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:49 -0700 Subject: [PATCH] ppc64 iSeries: irq simple cleanups This patch is just simple cleanups to the iSeries irq code. - whitespace and comments - rearrange some functions to avoid forward declarations - remove XmPciLpEvent.h as its functions were declared elsewhere - remove decaration of function that no longer exists No semantic changes. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/XmPciLpEvent.c b/arch/ppc64/kernel/XmPciLpEvent.c index 809c9bc..3db5307 100644 --- a/arch/ppc64/kernel/XmPciLpEvent.c +++ b/arch/ppc64/kernel/XmPciLpEvent.c @@ -1,9 +1,8 @@ /* - * File XmPciLpEvent.h created by Wayne Holm on Mon Jan 15 2001. + * File XmPciLpEvent.c created by Wayne Holm on Mon Jan 15 2001. * * This module handles PCI interrupt events sent by the iSeries Hypervisor. -*/ - + */ #include #include #include @@ -17,22 +16,22 @@ #include #include #include -#include +#include #include static long Pci_Interrupt_Count; static long Pci_Event_Count; enum XmPciLpEvent_Subtype { - XmPciLpEvent_BusCreated = 0, // PHB has been created - XmPciLpEvent_BusError = 1, // PHB has failed - XmPciLpEvent_BusFailed = 2, // Msg to Secondary, Primary failed bus - XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed - XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered - XmPciLpEvent_BusRecovered = 12, // PHB has been recovered - XmPciLpEvent_UnQuiesceBus = 18, // Secondary bus unqiescing - XmPciLpEvent_BridgeError = 21, // Bridge Error - XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt + XmPciLpEvent_BusCreated = 0, // PHB has been created + XmPciLpEvent_BusError = 1, // PHB has failed + XmPciLpEvent_BusFailed = 2, // Msg to Secondary, Primary failed bus + XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed + XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered + XmPciLpEvent_BusRecovered = 12, // PHB has been recovered + XmPciLpEvent_UnQuiesceBus = 18, // Secondary bus unqiescing + XmPciLpEvent_BridgeError = 21, // Bridge Error + XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt }; struct XmPciLpEvent_BusInterrupt { @@ -71,43 +70,6 @@ struct XmPciLpEvent { }; static void intReceived(struct XmPciLpEvent *eventParm, - struct pt_regs *regsParm); - -static void XmPciLpEvent_handler(struct HvLpEvent *eventParm, - struct pt_regs *regsParm) -{ -#ifdef CONFIG_PCI -#if 0 - PPCDBG(PPCDBG_BUSWALK, "XmPciLpEvent_handler, type 0x%x\n", - eventParm->xType); -#endif - ++Pci_Event_Count; - - if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) { - switch (eventParm->xFlags.xFunction) { - case HvLpEvent_Function_Int: - intReceived((struct XmPciLpEvent *)eventParm, regsParm); - break; - case HvLpEvent_Function_Ack: - printk(KERN_ERR - "XmPciLpEvent.c: unexpected ack received\n"); - break; - default: - printk(KERN_ERR - "XmPciLpEvent.c: unexpected event function %d\n", - (int)eventParm->xFlags.xFunction); - break; - } - } else if (eventParm) - printk(KERN_ERR - "XmPciLpEvent.c: Unrecognized PCI event type 0x%x\n", - (int)eventParm->xType); - else - printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n"); -#endif -} - -static void intReceived(struct XmPciLpEvent *eventParm, struct pt_regs *regsParm) { int irq; @@ -164,6 +126,39 @@ static void intReceived(struct XmPciLpEvent *eventParm, } } +static void XmPciLpEvent_handler(struct HvLpEvent *eventParm, + struct pt_regs *regsParm) +{ +#ifdef CONFIG_PCI +#if 0 + PPCDBG(PPCDBG_BUSWALK, "XmPciLpEvent_handler, type 0x%x\n", + eventParm->xType); +#endif + ++Pci_Event_Count; + + if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) { + switch (eventParm->xFlags.xFunction) { + case HvLpEvent_Function_Int: + intReceived((struct XmPciLpEvent *)eventParm, regsParm); + break; + case HvLpEvent_Function_Ack: + printk(KERN_ERR + "XmPciLpEvent.c: unexpected ack received\n"); + break; + default: + printk(KERN_ERR + "XmPciLpEvent.c: unexpected event function %d\n", + (int)eventParm->xFlags.xFunction); + break; + } + } else if (eventParm) + printk(KERN_ERR + "XmPciLpEvent.c: Unrecognized PCI event type 0x%x\n", + (int)eventParm->xType); + else + printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n"); +#endif +} /* This should be called sometime prior to buswalk (init_IRQ would be good) */ int XmPciLpEvent_init() @@ -179,12 +174,10 @@ int XmPciLpEvent_init() if (xRc == 0) { xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); if (xRc != 0) - printk(KERN_ERR - "XmPciLpEvent.c: open event path failed with rc 0x%x\n", - xRc); + printk(KERN_ERR "XmPciLpEvent.c: open event path " + "failed with rc 0x%x\n", xRc); } else - printk(KERN_ERR - "XmPciLpEvent.c: register handler failed with rc 0x%x\n", - xRc); + printk(KERN_ERR "XmPciLpEvent.c: register handler " + "failed with rc 0x%x\n", xRc); return xRc; } diff --git a/arch/ppc64/kernel/iSeries_irq.c b/arch/ppc64/kernel/iSeries_irq.c index f831d25..41902e3 100644 --- a/arch/ppc64/kernel/iSeries_irq.c +++ b/arch/ppc64/kernel/iSeries_irq.c @@ -1,27 +1,27 @@ -/************************************************************************/ -/* This module supports the iSeries PCI bus interrupt handling */ -/* Copyright (C) 20yy */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that 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., */ -/* 59 Temple Place, Suite 330, */ -/* Boston, MA 02111-1307 USA */ -/************************************************************************/ -/* Change Activity: */ -/* Created, December 13, 2000 by Wayne Holm */ -/* End Change Activity */ -/************************************************************************/ +/* + * This module supports the iSeries PCI bus interrupt handling + * Copyright (C) 20yy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * Change Activity: + * Created, December 13, 2000 by Wayne Holm + * End Change Activity + */ #include #include #include @@ -38,22 +38,6 @@ #include #include #include -#include - -static unsigned int iSeries_startup_IRQ(unsigned int irq); -static void iSeries_shutdown_IRQ(unsigned int irq); -static void iSeries_enable_IRQ(unsigned int irq); -static void iSeries_disable_IRQ(unsigned int irq); -static void iSeries_end_IRQ(unsigned int irq); - -static hw_irq_controller iSeries_IRQ_handler = { - .typename = "iSeries irq controller", - .startup = iSeries_startup_IRQ, - .shutdown = iSeries_shutdown_IRQ, - .enable = iSeries_enable_IRQ, - .disable = iSeries_disable_IRQ, - .end = iSeries_end_IRQ -}; /* This maps virtual irq numbers to real irqs */ unsigned int virt_irq_to_real_map[NR_IRQS]; @@ -69,30 +53,32 @@ void __init iSeries_init_IRQ(void) XmPciLpEvent_init(); } +#define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) +#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1) +#define REAL_IRQ_TO_FUNC(irq) ((irq) & 7) + /* - * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot - * It calculates the irq value for the slot. - * Note that subBusNumber is always 0 (at the moment at least). + * This will be called by device drivers (via enable_IRQ) + * to enable INTA in the bridge interrupt status register. */ -int __init iSeries_allocate_IRQ(HvBusNumber busNumber, - HvSubBusNumber subBusNumber, HvAgentId deviceId) +static void iSeries_enable_IRQ(unsigned int irq) { - unsigned int realirq, virtirq; - u8 idsel = (deviceId >> 4); - u8 function = deviceId & 7; + u32 bus, deviceId, function, mask; + const u32 subBus = 0; + unsigned int rirq = virt_irq_to_real_map[irq]; - virtirq = next_virtual_irq++; - realirq = ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function; - virt_irq_to_real_map[virtirq] = realirq; + /* The IRQ has already been locked by the caller */ + bus = REAL_IRQ_TO_BUS(rirq); + function = REAL_IRQ_TO_FUNC(rirq); + deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - irq_desc[virtirq].handler = &iSeries_IRQ_handler; - return virtirq; + /* Unmask secondary INTA */ + mask = 0x80000000; + HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask); + PPCDBG(PPCDBG_BUSWALK, "iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n", + bus, subBus, deviceId, irq); } -#define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) -#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1) -#define REAL_IRQ_TO_FUNC(irq) ((irq) & 7) - /* This is called by iSeries_activate_IRQs */ static unsigned int iSeries_startup_IRQ(unsigned int irq) { @@ -131,7 +117,7 @@ void __init iSeries_activate_IRQs() desc->handler->startup(irq); spin_unlock_irqrestore(&desc->lock, flags); } - } + } } /* this is not called anywhere currently */ @@ -173,29 +159,7 @@ static void iSeries_disable_IRQ(unsigned int irq) mask = 0x80000000; HvCallPci_maskInterrupts(bus, subBus, deviceId, mask); PPCDBG(PPCDBG_BUSWALK, "iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04X\n", - bus, subBus, deviceId, irq); -} - -/* - * This will be called by device drivers (via enable_IRQ) - * to enable INTA in the bridge interrupt status register. - */ -static void iSeries_enable_IRQ(unsigned int irq) -{ - u32 bus, deviceId, function, mask; - const u32 subBus = 0; - unsigned int rirq = virt_irq_to_real_map[irq]; - - /* The IRQ has already been locked by the caller */ - bus = REAL_IRQ_TO_BUS(rirq); - function = REAL_IRQ_TO_FUNC(rirq); - deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - - /* Unmask secondary INTA */ - mask = 0x80000000; - HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask); - PPCDBG(PPCDBG_BUSWALK, "iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n", - bus, subBus, deviceId, irq); + bus, subBus, deviceId, irq); } /* @@ -207,3 +171,32 @@ static void iSeries_enable_IRQ(unsigned int irq) static void iSeries_end_IRQ(unsigned int irq) { } + +static hw_irq_controller iSeries_IRQ_handler = { + .typename = "iSeries irq controller", + .startup = iSeries_startup_IRQ, + .shutdown = iSeries_shutdown_IRQ, + .enable = iSeries_enable_IRQ, + .disable = iSeries_disable_IRQ, + .end = iSeries_end_IRQ +}; + +/* + * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot + * It calculates the irq value for the slot. + * Note that subBusNumber is always 0 (at the moment at least). + */ +int __init iSeries_allocate_IRQ(HvBusNumber busNumber, + HvSubBusNumber subBusNumber, HvAgentId deviceId) +{ + unsigned int realirq, virtirq; + u8 idsel = (deviceId >> 4); + u8 function = deviceId & 7; + + virtirq = next_virtual_irq++; + realirq = ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function; + virt_irq_to_real_map[virtirq] = realirq; + + irq_desc[virtirq].handler = &iSeries_IRQ_handler; + return virtirq; +} diff --git a/include/asm-ppc64/iSeries/XmPciLpEvent.h b/include/asm-ppc64/iSeries/XmPciLpEvent.h deleted file mode 100644 index 4936627..0000000 --- a/include/asm-ppc64/iSeries/XmPciLpEvent.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __XMPCILPEVENT_H__ -#define __XMPCILPEVENT_H__ - -extern int XmPciLpEvent_init(void); -extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); - -#endif /* __XMPCILPEVENT_H__ */ diff --git a/include/asm-ppc64/iSeries/iSeries_irq.h b/include/asm-ppc64/iSeries/iSeries_irq.h index fbd5f52..a7c5bce 100644 --- a/include/asm-ppc64/iSeries/iSeries_irq.h +++ b/include/asm-ppc64/iSeries/iSeries_irq.h @@ -3,7 +3,6 @@ extern void iSeries_init_IRQ(void); extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId); -extern int iSeries_assign_IRQ(int, HvBusNumber, HvSubBusNumber, HvAgentId); extern void iSeries_activate_IRQs(void); extern int XmPciLpEvent_init(void); -- cgit v0.10.2 From 89ef68f0be53df6c4f1552fc329fe5abb1d5ed33 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:50 -0700 Subject: [PATCH] ppc64 iSeries: remove XmPciLpEvent.c This patch just merges XmPciLpEvent.c into iSeries_irq.c (the only caller of its only external function). XmPciLpEvent.c just contained the lowlevel iSeries irq code. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index ada9be8..ebf9b3c 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -21,7 +21,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o XmPciLpEvent.o \ +obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ HvCall.o HvLpConfig.o LparData.o \ iSeries_setup.o ItLpQueue.o hvCall.o \ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ diff --git a/arch/ppc64/kernel/XmPciLpEvent.c b/arch/ppc64/kernel/XmPciLpEvent.c deleted file mode 100644 index 3db5307..0000000 --- a/arch/ppc64/kernel/XmPciLpEvent.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * File XmPciLpEvent.c created by Wayne Holm on Mon Jan 15 2001. - * - * This module handles PCI interrupt events sent by the iSeries Hypervisor. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static long Pci_Interrupt_Count; -static long Pci_Event_Count; - -enum XmPciLpEvent_Subtype { - XmPciLpEvent_BusCreated = 0, // PHB has been created - XmPciLpEvent_BusError = 1, // PHB has failed - XmPciLpEvent_BusFailed = 2, // Msg to Secondary, Primary failed bus - XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed - XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered - XmPciLpEvent_BusRecovered = 12, // PHB has been recovered - XmPciLpEvent_UnQuiesceBus = 18, // Secondary bus unqiescing - XmPciLpEvent_BridgeError = 21, // Bridge Error - XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt -}; - -struct XmPciLpEvent_BusInterrupt { - HvBusNumber busNumber; - HvSubBusNumber subBusNumber; -}; - -struct XmPciLpEvent_NodeInterrupt { - HvBusNumber busNumber; - HvSubBusNumber subBusNumber; - HvAgentId deviceId; -}; - -struct XmPciLpEvent { - struct HvLpEvent hvLpEvent; - - union { - u64 alignData; // Align on an 8-byte boundary - - struct { - u32 fisr; - HvBusNumber busNumber; - HvSubBusNumber subBusNumber; - HvAgentId deviceId; - } slotInterrupt; - - struct XmPciLpEvent_BusInterrupt busFailed; - struct XmPciLpEvent_BusInterrupt busRecovered; - struct XmPciLpEvent_BusInterrupt busCreated; - - struct XmPciLpEvent_NodeInterrupt nodeFailed; - struct XmPciLpEvent_NodeInterrupt nodeRecovered; - - } eventData; - -}; - -static void intReceived(struct XmPciLpEvent *eventParm, - struct pt_regs *regsParm) -{ - int irq; - - ++Pci_Interrupt_Count; -#if 0 - PPCDBG(PPCDBG_BUSWALK, "PCI: XmPciLpEvent.c: intReceived\n"); -#endif - - switch (eventParm->hvLpEvent.xSubtype) { - case XmPciLpEvent_SlotInterrupt: - irq = eventParm->hvLpEvent.xCorrelationToken; - /* Dispatch the interrupt handlers for this irq */ - ppc_irq_dispatch_handler(regsParm, irq); - HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber, - eventParm->eventData.slotInterrupt.subBusNumber, - eventParm->eventData.slotInterrupt.deviceId); - break; - /* Ignore error recovery events for now */ - case XmPciLpEvent_BusCreated: - printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n", - eventParm->eventData.busCreated.busNumber); - break; - case XmPciLpEvent_BusError: - case XmPciLpEvent_BusFailed: - printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n", - eventParm->eventData.busFailed.busNumber); - break; - case XmPciLpEvent_BusRecovered: - case XmPciLpEvent_UnQuiesceBus: - printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n", - eventParm->eventData.busRecovered.busNumber); - break; - case XmPciLpEvent_NodeFailed: - case XmPciLpEvent_BridgeError: - printk(KERN_INFO - "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n", - eventParm->eventData.nodeFailed.busNumber, - eventParm->eventData.nodeFailed.subBusNumber, - eventParm->eventData.nodeFailed.deviceId); - break; - case XmPciLpEvent_NodeRecovered: - printk(KERN_INFO - "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n", - eventParm->eventData.nodeRecovered.busNumber, - eventParm->eventData.nodeRecovered.subBusNumber, - eventParm->eventData.nodeRecovered.deviceId); - break; - default: - printk(KERN_ERR - "XmPciLpEvent.c: unrecognized event subtype 0x%x\n", - eventParm->hvLpEvent.xSubtype); - break; - } -} - -static void XmPciLpEvent_handler(struct HvLpEvent *eventParm, - struct pt_regs *regsParm) -{ -#ifdef CONFIG_PCI -#if 0 - PPCDBG(PPCDBG_BUSWALK, "XmPciLpEvent_handler, type 0x%x\n", - eventParm->xType); -#endif - ++Pci_Event_Count; - - if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) { - switch (eventParm->xFlags.xFunction) { - case HvLpEvent_Function_Int: - intReceived((struct XmPciLpEvent *)eventParm, regsParm); - break; - case HvLpEvent_Function_Ack: - printk(KERN_ERR - "XmPciLpEvent.c: unexpected ack received\n"); - break; - default: - printk(KERN_ERR - "XmPciLpEvent.c: unexpected event function %d\n", - (int)eventParm->xFlags.xFunction); - break; - } - } else if (eventParm) - printk(KERN_ERR - "XmPciLpEvent.c: Unrecognized PCI event type 0x%x\n", - (int)eventParm->xType); - else - printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n"); -#endif -} - -/* This should be called sometime prior to buswalk (init_IRQ would be good) */ -int XmPciLpEvent_init() -{ - int xRc; - - PPCDBG(PPCDBG_BUSWALK, - "XmPciLpEvent_init, Register Event type 0x%04X\n", - HvLpEvent_Type_PciIo); - - xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, - &XmPciLpEvent_handler); - if (xRc == 0) { - xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); - if (xRc != 0) - printk(KERN_ERR "XmPciLpEvent.c: open event path " - "failed with rc 0x%x\n", xRc); - } else - printk(KERN_ERR "XmPciLpEvent.c: register handler " - "failed with rc 0x%x\n", xRc); - return xRc; -} diff --git a/arch/ppc64/kernel/iSeries_irq.c b/arch/ppc64/kernel/iSeries_irq.c index 41902e3..96a1f8c 100644 --- a/arch/ppc64/kernel/iSeries_irq.c +++ b/arch/ppc64/kernel/iSeries_irq.c @@ -1,6 +1,7 @@ /* * This module supports the iSeries PCI bus interrupt handling * Copyright (C) 20yy + * Copyright (C) 2004-2005 IBM Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +23,7 @@ * Created, December 13, 2000 by Wayne Holm * End Change Activity */ +#include #include #include #include @@ -30,11 +32,12 @@ #include #include #include - #include #include -#include +#include +#include +#include #include #include #include @@ -46,6 +49,169 @@ unsigned int virt_irq_to_real_map[NR_IRQS]; /* Note: the pcnet32 driver assumes irq numbers < 2 aren't valid. :( */ static int next_virtual_irq = 2; +static long Pci_Interrupt_Count; +static long Pci_Event_Count; + +enum XmPciLpEvent_Subtype { + XmPciLpEvent_BusCreated = 0, // PHB has been created + XmPciLpEvent_BusError = 1, // PHB has failed + XmPciLpEvent_BusFailed = 2, // Msg to Secondary, Primary failed bus + XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed + XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered + XmPciLpEvent_BusRecovered = 12, // PHB has been recovered + XmPciLpEvent_UnQuiesceBus = 18, // Secondary bus unqiescing + XmPciLpEvent_BridgeError = 21, // Bridge Error + XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt +}; + +struct XmPciLpEvent_BusInterrupt { + HvBusNumber busNumber; + HvSubBusNumber subBusNumber; +}; + +struct XmPciLpEvent_NodeInterrupt { + HvBusNumber busNumber; + HvSubBusNumber subBusNumber; + HvAgentId deviceId; +}; + +struct XmPciLpEvent { + struct HvLpEvent hvLpEvent; + + union { + u64 alignData; // Align on an 8-byte boundary + + struct { + u32 fisr; + HvBusNumber busNumber; + HvSubBusNumber subBusNumber; + HvAgentId deviceId; + } slotInterrupt; + + struct XmPciLpEvent_BusInterrupt busFailed; + struct XmPciLpEvent_BusInterrupt busRecovered; + struct XmPciLpEvent_BusInterrupt busCreated; + + struct XmPciLpEvent_NodeInterrupt nodeFailed; + struct XmPciLpEvent_NodeInterrupt nodeRecovered; + + } eventData; + +}; + +static void intReceived(struct XmPciLpEvent *eventParm, + struct pt_regs *regsParm) +{ + int irq; + + ++Pci_Interrupt_Count; +#if 0 + PPCDBG(PPCDBG_BUSWALK, "PCI: XmPciLpEvent.c: intReceived\n"); +#endif + + switch (eventParm->hvLpEvent.xSubtype) { + case XmPciLpEvent_SlotInterrupt: + irq = eventParm->hvLpEvent.xCorrelationToken; + /* Dispatch the interrupt handlers for this irq */ + ppc_irq_dispatch_handler(regsParm, irq); + HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber, + eventParm->eventData.slotInterrupt.subBusNumber, + eventParm->eventData.slotInterrupt.deviceId); + break; + /* Ignore error recovery events for now */ + case XmPciLpEvent_BusCreated: + printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n", + eventParm->eventData.busCreated.busNumber); + break; + case XmPciLpEvent_BusError: + case XmPciLpEvent_BusFailed: + printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n", + eventParm->eventData.busFailed.busNumber); + break; + case XmPciLpEvent_BusRecovered: + case XmPciLpEvent_UnQuiesceBus: + printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n", + eventParm->eventData.busRecovered.busNumber); + break; + case XmPciLpEvent_NodeFailed: + case XmPciLpEvent_BridgeError: + printk(KERN_INFO + "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n", + eventParm->eventData.nodeFailed.busNumber, + eventParm->eventData.nodeFailed.subBusNumber, + eventParm->eventData.nodeFailed.deviceId); + break; + case XmPciLpEvent_NodeRecovered: + printk(KERN_INFO + "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n", + eventParm->eventData.nodeRecovered.busNumber, + eventParm->eventData.nodeRecovered.subBusNumber, + eventParm->eventData.nodeRecovered.deviceId); + break; + default: + printk(KERN_ERR + "XmPciLpEvent.c: unrecognized event subtype 0x%x\n", + eventParm->hvLpEvent.xSubtype); + break; + } +} + +static void XmPciLpEvent_handler(struct HvLpEvent *eventParm, + struct pt_regs *regsParm) +{ +#ifdef CONFIG_PCI +#if 0 + PPCDBG(PPCDBG_BUSWALK, "XmPciLpEvent_handler, type 0x%x\n", + eventParm->xType); +#endif + ++Pci_Event_Count; + + if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) { + switch (eventParm->xFlags.xFunction) { + case HvLpEvent_Function_Int: + intReceived((struct XmPciLpEvent *)eventParm, regsParm); + break; + case HvLpEvent_Function_Ack: + printk(KERN_ERR + "XmPciLpEvent.c: unexpected ack received\n"); + break; + default: + printk(KERN_ERR + "XmPciLpEvent.c: unexpected event function %d\n", + (int)eventParm->xFlags.xFunction); + break; + } + } else if (eventParm) + printk(KERN_ERR + "XmPciLpEvent.c: Unrecognized PCI event type 0x%x\n", + (int)eventParm->xType); + else + printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n"); +#endif +} + +/* This should be called sometime prior to buswalk (init_IRQ would be good) */ +int XmPciLpEvent_init() +{ + int xRc; + + PPCDBG(PPCDBG_BUSWALK, + "XmPciLpEvent_init, Register Event type 0x%04X\n", + HvLpEvent_Type_PciIo); + + xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, + &XmPciLpEvent_handler); + if (xRc == 0) { + xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); + if (xRc != 0) + printk(KERN_ERR "XmPciLpEvent.c: open event path " + "failed with rc 0x%x\n", xRc); + } else + printk(KERN_ERR "XmPciLpEvent.c: register handler " + "failed with rc 0x%x\n", xRc); + return xRc; +} + /* This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c */ void __init iSeries_init_IRQ(void) { -- cgit v0.10.2 From 7f74e79fe749da035cc150446f02aec29938a5c8 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:51 -0700 Subject: [PATCH] ppc64 iSeries: tidy up irq code after merge This patch just removes some dead code, fixes messages that referred to the file this code used to be in and inserts XmPciLpEvent_init into its caller. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/iSeries_irq.c b/arch/ppc64/kernel/iSeries_irq.c index 96a1f8c..77376c1 100644 --- a/arch/ppc64/kernel/iSeries_irq.c +++ b/arch/ppc64/kernel/iSeries_irq.c @@ -105,9 +105,6 @@ static void intReceived(struct XmPciLpEvent *eventParm, int irq; ++Pci_Interrupt_Count; -#if 0 - PPCDBG(PPCDBG_BUSWALK, "PCI: XmPciLpEvent.c: intReceived\n"); -#endif switch (eventParm->hvLpEvent.xSubtype) { case XmPciLpEvent_SlotInterrupt: @@ -120,37 +117,37 @@ static void intReceived(struct XmPciLpEvent *eventParm, break; /* Ignore error recovery events for now */ case XmPciLpEvent_BusCreated: - printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n", + printk(KERN_INFO "intReceived: system bus %d created\n", eventParm->eventData.busCreated.busNumber); break; case XmPciLpEvent_BusError: case XmPciLpEvent_BusFailed: - printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n", + printk(KERN_INFO "intReceived: system bus %d failed\n", eventParm->eventData.busFailed.busNumber); break; case XmPciLpEvent_BusRecovered: case XmPciLpEvent_UnQuiesceBus: - printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n", + printk(KERN_INFO "intReceived: system bus %d recovered\n", eventParm->eventData.busRecovered.busNumber); break; case XmPciLpEvent_NodeFailed: case XmPciLpEvent_BridgeError: printk(KERN_INFO - "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n", + "intReceived: multi-adapter bridge %d/%d/%d failed\n", eventParm->eventData.nodeFailed.busNumber, eventParm->eventData.nodeFailed.subBusNumber, eventParm->eventData.nodeFailed.deviceId); break; case XmPciLpEvent_NodeRecovered: printk(KERN_INFO - "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n", + "intReceived: multi-adapter bridge %d/%d/%d recovered\n", eventParm->eventData.nodeRecovered.busNumber, eventParm->eventData.nodeRecovered.subBusNumber, eventParm->eventData.nodeRecovered.deviceId); break; default: printk(KERN_ERR - "XmPciLpEvent.c: unrecognized event subtype 0x%x\n", + "intReceived: unrecognized event subtype 0x%x\n", eventParm->hvLpEvent.xSubtype); break; } @@ -160,10 +157,6 @@ static void XmPciLpEvent_handler(struct HvLpEvent *eventParm, struct pt_regs *regsParm) { #ifdef CONFIG_PCI -#if 0 - PPCDBG(PPCDBG_BUSWALK, "XmPciLpEvent_handler, type 0x%x\n", - eventParm->xType); -#endif ++Pci_Event_Count; if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) { @@ -173,50 +166,42 @@ static void XmPciLpEvent_handler(struct HvLpEvent *eventParm, break; case HvLpEvent_Function_Ack: printk(KERN_ERR - "XmPciLpEvent.c: unexpected ack received\n"); + "XmPciLpEvent_handler: unexpected ack received\n"); break; default: printk(KERN_ERR - "XmPciLpEvent.c: unexpected event function %d\n", + "XmPciLpEvent_handler: unexpected event function %d\n", (int)eventParm->xFlags.xFunction); break; } } else if (eventParm) printk(KERN_ERR - "XmPciLpEvent.c: Unrecognized PCI event type 0x%x\n", + "XmPciLpEvent_handler: Unrecognized PCI event type 0x%x\n", (int)eventParm->xType); else - printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n"); + printk(KERN_ERR "XmPciLpEvent_handler: NULL event received\n"); #endif } -/* This should be called sometime prior to buswalk (init_IRQ would be good) */ -int XmPciLpEvent_init() +/* + * This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c + * It must be called before the bus walk. + */ +void __init iSeries_init_IRQ(void) { + /* Register PCI event handler and open an event path */ int xRc; - PPCDBG(PPCDBG_BUSWALK, - "XmPciLpEvent_init, Register Event type 0x%04X\n", - HvLpEvent_Type_PciIo); - xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, &XmPciLpEvent_handler); if (xRc == 0) { xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); if (xRc != 0) - printk(KERN_ERR "XmPciLpEvent.c: open event path " + printk(KERN_ERR "iSeries_init_IRQ: open event path " "failed with rc 0x%x\n", xRc); } else - printk(KERN_ERR "XmPciLpEvent.c: register handler " + printk(KERN_ERR "iSeries_init_IRQ: register handler " "failed with rc 0x%x\n", xRc); - return xRc; -} - -/* This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c */ -void __init iSeries_init_IRQ(void) -{ - /* Register PCI event handler and open an event path */ - XmPciLpEvent_init(); } #define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) diff --git a/include/asm-ppc64/iSeries/iSeries_irq.h b/include/asm-ppc64/iSeries/iSeries_irq.h index a7c5bce..6c9767a 100644 --- a/include/asm-ppc64/iSeries/iSeries_irq.h +++ b/include/asm-ppc64/iSeries/iSeries_irq.h @@ -5,6 +5,4 @@ extern void iSeries_init_IRQ(void); extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId); extern void iSeries_activate_IRQs(void); -extern int XmPciLpEvent_init(void); - #endif /* __ISERIES_IRQ_H__ */ -- cgit v0.10.2 From 145d01e4287b8cbf50f87c3283e33bf5c84e8468 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:52 -0700 Subject: [PATCH] ppc64 iSeries: allow build with no PCI This patch allows iSeries to build with CONFIG_PCI=n. This is useful for partitions that have only virtual I/O. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 5cb3438..0f1fa28 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -323,7 +323,7 @@ config EISA bool config PCI - bool + bool "support for PCI devices" if (EMBEDDED && PPC_ISERIES) default y help Find out whether your system includes a PCI bus. PCI is the name of diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index ebf9b3c..b5e167c 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -16,13 +16,13 @@ obj-y += vdso32/ vdso64/ obj-$(CONFIG_PPC_OF) += of_device.o -pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_VpdInfo.o +pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_irq.o \ + iSeries_VpdInfo.o pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ - HvCall.o HvLpConfig.o LparData.o \ +obj-$(CONFIG_PPC_ISERIES) += HvCall.o HvLpConfig.o LparData.o \ iSeries_setup.o ItLpQueue.o hvCall.o \ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o diff --git a/arch/ppc64/kernel/dma.c b/arch/ppc64/kernel/dma.c index ce714c9..4da8e31 100644 --- a/arch/ppc64/kernel/dma.c +++ b/arch/ppc64/kernel/dma.c @@ -15,8 +15,10 @@ static struct dma_mapping_ops *get_dma_ops(struct device *dev) { +#ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) return &pci_dma_ops; +#endif #ifdef CONFIG_IBMVIO if (dev->bus == &vio_bus_type) return &vio_dma_ops; @@ -37,8 +39,10 @@ EXPORT_SYMBOL(dma_supported); int dma_set_mask(struct device *dev, u64 dma_mask) { +#ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) return pci_set_dma_mask(to_pci_dev(dev), dma_mask); +#endif #ifdef CONFIG_IBMVIO if (dev->bus == &vio_bus_type) return -EIO; diff --git a/arch/ppc64/kernel/iSeries_iommu.c b/arch/ppc64/kernel/iSeries_iommu.c index 4e1a47c..f8ff1bb 100644 --- a/arch/ppc64/kernel/iSeries_iommu.c +++ b/arch/ppc64/kernel/iSeries_iommu.c @@ -83,7 +83,7 @@ static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages) } } - +#ifdef CONFIG_PCI /* * This function compares the known tables to find an iommu_table * that has already been built for hardware TCEs. @@ -159,6 +159,7 @@ void iommu_devnode_init_iSeries(struct iSeries_Device_Node *dn) else kfree(tbl); } +#endif static void iommu_dev_setup_iSeries(struct pci_dev *dev) { } static void iommu_bus_setup_iSeries(struct pci_bus *bus) { } diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 3d3ed63..b319624 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -76,7 +76,11 @@ extern void ppcdbg_initialize(void); static void build_iSeries_Memory_Map(void); static void setup_iSeries_cache_sizes(void); static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr); +#ifdef CONFIG_PCI extern void iSeries_pci_final_fixup(void); +#else +static void iSeries_pci_final_fixup(void) { } +#endif /* Global Variables */ static unsigned long procFreqHz; @@ -876,6 +880,10 @@ static int set_spread_lpevents(char *str) } __setup("spread_lpevents=", set_spread_lpevents); +#ifndef CONFIG_PCI +void __init iSeries_init_IRQ(void) { } +#endif + void __init iSeries_early_setup(void) { iSeries_fixup_klimit(); diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c index 9c8e317..118436e 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/ppc64/kernel/sys_ppc32.c @@ -741,6 +741,7 @@ asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubu asmlinkage int sys32_pciconfig_iobase(u32 which, u32 in_bus, u32 in_devfn) { +#ifdef CONFIG_PCI struct pci_controller* hose; struct list_head *ln; struct pci_bus *bus = NULL; @@ -786,7 +787,7 @@ asmlinkage int sys32_pciconfig_iobase(u32 which, u32 in_bus, u32 in_devfn) case IOBASE_ISA_MEM: return -EINVAL; } - +#endif /* CONFIG_PCI */ return -EOPNOTSUPP; } diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index bf7b5bb..76fbfa9 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -12,7 +12,7 @@ lib-$(CONFIG_SMP) += locks.o # e2a provides EBCDIC to ASCII conversions. ifdef CONFIG_PPC_ISERIES -obj-$(CONFIG_PCI) += e2a.o +obj-y += e2a.o endif lib-$(CONFIG_DEBUG_KERNEL) += sstep.o diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 257b8ee..e3085b2 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -484,7 +484,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, return virtr + wrote; } -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)) static ssize_t read_port(struct file * file, char __user * buf, size_t count, loff_t *ppos) { @@ -744,7 +744,7 @@ static struct file_operations null_fops = { .write = write_null, }; -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)) static struct file_operations port_fops = { .llseek = memory_lseek, .read = read_port, @@ -804,7 +804,7 @@ static int memory_open(struct inode * inode, struct file * filp) case 3: filp->f_op = &null_fops; break; -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)) case 4: filp->f_op = &port_fops; break; @@ -846,7 +846,7 @@ static const struct { {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, {3, "null", S_IRUGO | S_IWUGO, &null_fops}, -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)) {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, #endif {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 6e44b46..6a15703 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -753,7 +753,7 @@ config SERIAL_MPC52xx_CONSOLE_BAUD config SERIAL_ICOM tristate "IBM Multiport Serial Adapter" - depends on PPC_ISERIES || PPC_PSERIES + depends on PCI && (PPC_ISERIES || PPC_PSERIES) select SERIAL_CORE help This driver is for a family of multiport serial adapters diff --git a/include/asm-ppc64/dma.h b/include/asm-ppc64/dma.h index d693b80..dfd1f69 100644 --- a/include/asm-ppc64/dma.h +++ b/include/asm-ppc64/dma.h @@ -27,6 +27,8 @@ /* Doesn't really apply... */ #define MAX_DMA_ADDRESS (~0UL) +#if !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) + #define dma_outb outb #define dma_inb inb @@ -323,4 +325,5 @@ extern int isa_dma_bridge_buggy; #else #define isa_dma_bridge_buggy (0) #endif +#endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */ #endif /* _ASM_DMA_H */ diff --git a/include/asm-ppc64/iommu.h b/include/asm-ppc64/iommu.h index d9b5337..729de5c 100644 --- a/include/asm-ppc64/iommu.h +++ b/include/asm-ppc64/iommu.h @@ -137,8 +137,12 @@ extern void iommu_init_early_pSeries(void); extern void iommu_init_early_iSeries(void); extern void iommu_init_early_u3(void); +#ifdef CONFIG_PCI extern void pci_iommu_init(void); extern void pci_direct_iommu_init(void); +#else +static inline void pci_iommu_init(void) { } +#endif extern void alloc_u3_dart_table(void); -- cgit v0.10.2 From ac5b33c9bcf1c05ae949b026a51d7f8f9573591c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 21 Jun 2005 17:15:54 -0700 Subject: [PATCH] ppc64: tidy up vio devices fake parent Currently we dynamically allocate the fake parent device for all devices on the vio bus. This patch statically allocates it. This also allows us to reuse it for the iSeries "generic" vio device (that is used for passing to dma routines when communicating with the hypervisor without a device involved). Also unexport vio_bus_type as it is never used in modules. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c index 79f2dc7..0c0ba71 100644 --- a/arch/ppc64/kernel/vio.c +++ b/arch/ppc64/kernel/vio.c @@ -41,20 +41,25 @@ static const struct vio_device_id *vio_match_device( static struct iommu_table *vio_build_iommu_table(struct vio_dev *); static int vio_num_address_cells; #endif -static struct vio_dev *vio_bus_device; /* fake "parent" device */ - #ifdef CONFIG_PPC_ISERIES -static struct vio_dev *__init vio_register_device_iseries(char *type, - uint32_t unit_num); - static struct iommu_table veth_iommu_table; static struct iommu_table vio_iommu_table; - -static struct vio_dev _vio_dev = { +#endif +static struct vio_dev vio_bus_device = { /* fake "parent" device */ + .name = vio_bus_device.dev.bus_id, + .type = "", +#ifdef CONFIG_PPC_ISERIES .iommu_table = &vio_iommu_table, - .dev.bus = &vio_bus_type +#endif + .dev.bus_id = "vio", + .dev.bus = &vio_bus_type, }; -struct device *iSeries_vio_dev = &_vio_dev.dev; + +#ifdef CONFIG_PPC_ISERIES +static struct vio_dev *__init vio_register_device_iseries(char *type, + uint32_t unit_num); + +struct device *iSeries_vio_dev = &vio_bus_device.dev; EXPORT_SYMBOL(iSeries_vio_dev); #define device_is_compatible(a, b) 1 @@ -260,18 +265,10 @@ static int __init vio_bus_init(void) } /* the fake parent of all vio devices, just to give us a nice directory */ - vio_bus_device = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); - if (!vio_bus_device) { - return 1; - } - memset(vio_bus_device, 0, sizeof(struct vio_dev)); - strcpy(vio_bus_device->dev.bus_id, "vio"); - - err = device_register(&vio_bus_device->dev); + err = device_register(&vio_bus_device.dev); if (err) { printk(KERN_WARNING "%s: device_register returned %i\n", __FUNCTION__, err); - kfree(vio_bus_device); return err; } @@ -326,7 +323,7 @@ static struct vio_dev * __devinit vio_register_device_common( viodev->unit_address = unit_address; viodev->iommu_table = iommu_table; /* init generic 'struct device' fields: */ - viodev->dev.parent = &vio_bus_device->dev; + viodev->dev.parent = &vio_bus_device.dev; viodev->dev.bus = &vio_bus_type; viodev->dev.release = vio_dev_release; @@ -636,5 +633,3 @@ struct bus_type vio_bus_type = { .name = "vio", .match = vio_bus_match, }; - -EXPORT_SYMBOL(vio_bus_type); -- cgit v0.10.2 From 515bae9cdc6a78eda0879e1f158056d73ec808b7 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 21 Jun 2005 17:15:55 -0700 Subject: [PATCH] ppc64: Mark kernel hptes dirty We dont use the hardware referenced and changed bits and setting them early avoids a store to memory. We already do this for userspace hptes but not kernel ones. Do it. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c index 87d0525..1647b1c 100644 --- a/arch/ppc64/mm/hash_utils.c +++ b/arch/ppc64/mm/hash_utils.c @@ -195,7 +195,7 @@ void __init htab_initialize(void) memset((void *)table, 0, htab_size_bytes); } - mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; + mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX; /* On U3 based machines, we need to reserve the DART area and * _NOT_ map it to avoid cache paradoxes as it's remapped non -- cgit v0.10.2 From 9b843cda193c56f5e12fedeaf95e0126b706d57b Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 21 Jun 2005 17:15:55 -0700 Subject: [PATCH] ppc64: set/clear SMT capable bit at boot Allow the SMT bit to be set/reset at boot, like the ALTIVEC bit. This means we will enable SMT on unknown cpus that support it. Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c index eb6538b..47727a6 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c @@ -884,6 +884,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, { char *type = get_flat_dt_prop(node, "device_type", NULL); u32 *prop; + unsigned long size; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) @@ -929,6 +930,17 @@ static int __init early_init_dt_scan_cpus(unsigned long node, cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; } + /* + * Check for an SMT capable CPU and set the CPU feature. We do + * this by looking at the size of the ibm,ppc-interrupt-server#s + * property + */ + prop = (u32 *)get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", + &size); + cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT; + if (prop && ((size / sizeof(u32)) > 1)) + cur_cpu_spec->cpu_features |= CPU_FTR_SMT; + return 0; } -- cgit v0.10.2 From e400bae98499583767da58fb0a1b9ad3e24fcb86 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 21 Jun 2005 17:15:56 -0700 Subject: [PATCH] mips: add vr41xx gpio support Add vr41xx gpio support. Signed-off-by: Yoichi Yuasa Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 5ed6515..7ccf871 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -929,6 +929,10 @@ config SCx200_GPIO If compiled as a module, it will be called scx200_gpio. +config GPIO_VR41XX + tristate "NEC VR4100 series General-purpose I/O Unit support" + depends on CPU_VR41XX + config RAW_DRIVER tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)" help diff --git a/drivers/char/Makefile b/drivers/char/Makefile index e3f5c32..1aff819 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o +obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_TANBAC_TB0219) += tb0219.o obj-$(CONFIG_WATCHDOG) += watchdog/ diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c new file mode 100644 index 0000000..683278b --- /dev/null +++ b/drivers/char/vr41xx_giu.c @@ -0,0 +1,743 @@ +/* + * Driver for NEC VR4100 series General-purpose I/O Unit. + * + * Copyright (C) 2002 MontaVista Software Inc. + * Author: Yoichi Yuasa + * Copyright (C) 2003-2005 Yoichi Yuasa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +MODULE_AUTHOR("Yoichi Yuasa "); +MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver"); +MODULE_LICENSE("GPL"); + +static int major; /* default is dynamic major device number */ +module_param(major, int, 0); +MODULE_PARM_DESC(major, "Major device number"); + +#define GIU_TYPE1_START 0x0b000100UL +#define GIU_TYPE1_SIZE 0x20UL + +#define GIU_TYPE2_START 0x0f000140UL +#define GIU_TYPE2_SIZE 0x20UL + +#define GIU_TYPE3_START 0x0f000140UL +#define GIU_TYPE3_SIZE 0x28UL + +#define GIU_PULLUPDOWN_START 0x0b0002e0UL +#define GIU_PULLUPDOWN_SIZE 0x04UL + +#define GIUIOSELL 0x00 +#define GIUIOSELH 0x02 +#define GIUPIODL 0x04 +#define GIUPIODH 0x06 +#define GIUINTSTATL 0x08 +#define GIUINTSTATH 0x0a +#define GIUINTENL 0x0c +#define GIUINTENH 0x0e +#define GIUINTTYPL 0x10 +#define GIUINTTYPH 0x12 +#define GIUINTALSELL 0x14 +#define GIUINTALSELH 0x16 +#define GIUINTHTSELL 0x18 +#define GIUINTHTSELH 0x1a +#define GIUPODATL 0x1c +#define GIUPODATEN 0x1c +#define GIUPODATH 0x1e + #define PIOEN0 0x0100 + #define PIOEN1 0x0200 +#define GIUPODAT 0x1e +#define GIUFEDGEINHL 0x20 +#define GIUFEDGEINHH 0x22 +#define GIUREDGEINHL 0x24 +#define GIUREDGEINHH 0x26 + +#define GIUUSEUPDN 0x1e0 +#define GIUTERMUPDN 0x1e2 + +#define GPIO_HAS_PULLUPDOWN_IO 0x0001 +#define GPIO_HAS_OUTPUT_ENABLE 0x0002 +#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100 + +static spinlock_t giu_lock; +static struct resource *giu_resource1; +static struct resource *giu_resource2; +static unsigned long giu_flags; +static unsigned int giu_nr_pins; + +static void __iomem *giu_base; + +#define giu_read(offset) readw(giu_base + (offset)) +#define giu_write(offset, value) writew((value), giu_base + (offset)) + +#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE) +#define GIUINT_HIGH_OFFSET 16 +#define GIUINT_HIGH_MAX 32 + +static inline uint16_t giu_set(uint16_t offset, uint16_t set) +{ + uint16_t data; + + data = giu_read(offset); + data |= set; + giu_write(offset, data); + + return data; +} + +static inline uint16_t giu_clear(uint16_t offset, uint16_t clear) +{ + uint16_t data; + + data = giu_read(offset); + data &= ~clear; + giu_write(offset, data); + + return data; +} + +static unsigned int startup_giuint_low_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GPIO_PIN_OF_IRQ(irq); + giu_write(GIUINTSTATL, 1 << pin); + giu_set(GIUINTENL, 1 << pin); + + return 0; +} + +static void shutdown_giuint_low_irq(unsigned int irq) +{ + giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); +} + +static void enable_giuint_low_irq(unsigned int irq) +{ + giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); +} + +#define disable_giuint_low_irq shutdown_giuint_low_irq + +static void ack_giuint_low_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GPIO_PIN_OF_IRQ(irq); + giu_clear(GIUINTENL, 1 << pin); + giu_write(GIUINTSTATL, 1 << pin); +} + +static void end_giuint_low_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); +} + +static struct hw_interrupt_type giuint_low_irq_type = { + .typename = "GIUINTL", + .startup = startup_giuint_low_irq, + .shutdown = shutdown_giuint_low_irq, + .enable = enable_giuint_low_irq, + .disable = disable_giuint_low_irq, + .ack = ack_giuint_low_irq, + .end = end_giuint_low_irq, +}; + +static unsigned int startup_giuint_high_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; + giu_write(GIUINTSTATH, 1 << pin); + giu_set(GIUINTENH, 1 << pin); + + return 0; +} + +static void shutdown_giuint_high_irq(unsigned int irq) +{ + giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); +} + +static void enable_giuint_high_irq(unsigned int irq) +{ + giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); +} + +#define disable_giuint_high_irq shutdown_giuint_high_irq + +static void ack_giuint_high_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; + giu_clear(GIUINTENH, 1 << pin); + giu_write(GIUINTSTATH, 1 << pin); +} + +static void end_giuint_high_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); +} + +static struct hw_interrupt_type giuint_high_irq_type = { + .typename = "GIUINTH", + .startup = startup_giuint_high_irq, + .shutdown = shutdown_giuint_high_irq, + .enable = enable_giuint_high_irq, + .disable = disable_giuint_high_irq, + .ack = ack_giuint_high_irq, + .end = end_giuint_high_irq, +}; + +static int giu_get_irq(unsigned int irq, struct pt_regs *regs) +{ + uint16_t pendl, pendh, maskl, maskh; + int i; + + pendl = giu_read(GIUINTSTATL); + pendh = giu_read(GIUINTSTATH); + maskl = giu_read(GIUINTENL); + maskh = giu_read(GIUINTENH); + + maskl &= pendl; + maskh &= pendh; + + if (maskl) { + for (i = 0; i < 16; i++) { + if (maskl & (1 << i)) + return GIU_IRQ(i); + } + } else if (maskh) { + for (i = 0; i < 16; i++) { + if (maskh & (1 << i)) + return GIU_IRQ(i + GIUINT_HIGH_OFFSET); + } + } + + printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", + maskl, pendl, maskh, pendh); + + atomic_inc(&irq_err_count); + + return -EINVAL; +} + +void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal) +{ + uint16_t mask; + + if (pin < GIUINT_HIGH_OFFSET) { + mask = 1 << pin; + if (trigger != IRQ_TRIGGER_LEVEL) { + giu_set(GIUINTTYPL, mask); + if (signal == IRQ_SIGNAL_HOLD) + giu_set(GIUINTHTSELL, mask); + else + giu_clear(GIUINTHTSELL, mask); + if (current_cpu_data.cputype == CPU_VR4133) { + switch (trigger) { + case IRQ_TRIGGER_EDGE_FALLING: + giu_set(GIUFEDGEINHL, mask); + giu_clear(GIUREDGEINHL, mask); + break; + case IRQ_TRIGGER_EDGE_RISING: + giu_clear(GIUFEDGEINHL, mask); + giu_set(GIUREDGEINHL, mask); + break; + default: + giu_set(GIUFEDGEINHL, mask); + giu_set(GIUREDGEINHL, mask); + break; + } + } + } else { + giu_clear(GIUINTTYPL, mask); + giu_clear(GIUINTHTSELL, mask); + } + giu_write(GIUINTSTATL, mask); + } else if (pin < GIUINT_HIGH_MAX) { + mask = 1 << (pin - GIUINT_HIGH_OFFSET); + if (trigger != IRQ_TRIGGER_LEVEL) { + giu_set(GIUINTTYPH, mask); + if (signal == IRQ_SIGNAL_HOLD) + giu_set(GIUINTHTSELH, mask); + else + giu_clear(GIUINTHTSELH, mask); + if (current_cpu_data.cputype == CPU_VR4133) { + switch (trigger) { + case IRQ_TRIGGER_EDGE_FALLING: + giu_set(GIUFEDGEINHH, mask); + giu_clear(GIUREDGEINHH, mask); + break; + case IRQ_TRIGGER_EDGE_RISING: + giu_clear(GIUFEDGEINHH, mask); + giu_set(GIUREDGEINHH, mask); + break; + default: + giu_set(GIUFEDGEINHH, mask); + giu_set(GIUREDGEINHH, mask); + break; + } + } + } else { + giu_clear(GIUINTTYPH, mask); + giu_clear(GIUINTHTSELH, mask); + } + giu_write(GIUINTSTATH, mask); + } +} + +EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger); + +void vr41xx_set_irq_level(unsigned int pin, irq_level_t level) +{ + uint16_t mask; + + if (pin < GIUINT_HIGH_OFFSET) { + mask = 1 << pin; + if (level == IRQ_LEVEL_HIGH) + giu_set(GIUINTALSELL, mask); + else + giu_clear(GIUINTALSELL, mask); + giu_write(GIUINTSTATL, mask); + } else if (pin < GIUINT_HIGH_MAX) { + mask = 1 << (pin - GIUINT_HIGH_OFFSET); + if (level == IRQ_LEVEL_HIGH) + giu_set(GIUINTALSELH, mask); + else + giu_clear(GIUINTALSELH, mask); + giu_write(GIUINTSTATH, mask); + } +} + +EXPORT_SYMBOL_GPL(vr41xx_set_irq_level); + +gpio_data_t vr41xx_gpio_get_pin(unsigned int pin) +{ + uint16_t reg, mask; + + if (pin >= giu_nr_pins) + return GPIO_DATA_INVAL; + + if (pin < 16) { + reg = giu_read(GIUPIODL); + mask = (uint16_t)1 << pin; + } else if (pin < 32) { + reg = giu_read(GIUPIODH); + mask = (uint16_t)1 << (pin - 16); + } else if (pin < 48) { + reg = giu_read(GIUPODATL); + mask = (uint16_t)1 << (pin - 32); + } else { + reg = giu_read(GIUPODATH); + mask = (uint16_t)1 << (pin - 48); + } + + if (reg & mask) + return GPIO_DATA_HIGH; + + return GPIO_DATA_LOW; +} + +EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin); + +int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data) +{ + uint16_t offset, mask, reg; + unsigned long flags; + + if (pin >= giu_nr_pins) + return -EINVAL; + + if (pin < 16) { + offset = GIUPIODL; + mask = (uint16_t)1 << pin; + } else if (pin < 32) { + offset = GIUPIODH; + mask = (uint16_t)1 << (pin - 16); + } else if (pin < 48) { + offset = GIUPODATL; + mask = (uint16_t)1 << (pin - 32); + } else { + offset = GIUPODATH; + mask = (uint16_t)1 << (pin - 48); + } + + spin_lock_irqsave(&giu_lock, flags); + + reg = giu_read(offset); + if (data == GPIO_DATA_HIGH) + reg |= mask; + else + reg &= ~mask; + giu_write(offset, reg); + + spin_unlock_irqrestore(&giu_lock, flags); + + return 0; +} + +EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin); + +int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir) +{ + uint16_t offset, mask, reg; + unsigned long flags; + + if (pin >= giu_nr_pins) + return -EINVAL; + + if (pin < 16) { + offset = GIUIOSELL; + mask = (uint16_t)1 << pin; + } else if (pin < 32) { + offset = GIUIOSELH; + mask = (uint16_t)1 << (pin - 16); + } else { + if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) { + offset = GIUPODATEN; + mask = (uint16_t)1 << (pin - 32); + } else { + switch (pin) { + case 48: + offset = GIUPODATH; + mask = PIOEN0; + break; + case 49: + offset = GIUPODATH; + mask = PIOEN1; + break; + default: + return -EINVAL; + } + } + } + + spin_lock_irqsave(&giu_lock, flags); + + reg = giu_read(offset); + if (dir == GPIO_OUTPUT) + reg |= mask; + else + reg &= ~mask; + giu_write(offset, reg); + + spin_unlock_irqrestore(&giu_lock, flags); + + return 0; +} + +EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction); + +int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull) +{ + uint16_t reg, mask; + unsigned long flags; + + if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO) + return -EPERM; + + if (pin >= 15) + return -EINVAL; + + mask = (uint16_t)1 << pin; + + spin_lock_irqsave(&giu_lock, flags); + + if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) { + reg = giu_read(GIUTERMUPDN); + if (pull == GPIO_PULL_UP) + reg |= mask; + else + reg &= ~mask; + giu_write(GIUTERMUPDN, reg); + + reg = giu_read(GIUUSEUPDN); + reg |= mask; + giu_write(GIUUSEUPDN, reg); + } else { + reg = giu_read(GIUUSEUPDN); + reg &= ~mask; + giu_write(GIUUSEUPDN, reg); + } + + spin_unlock_irqrestore(&giu_lock, flags); + + return 0; +} + +EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown); + +static ssize_t gpio_read(struct file *file, char __user *buf, size_t len, + loff_t *ppos) +{ + unsigned int pin; + char value = '0'; + + pin = iminor(file->f_dentry->d_inode); + if (pin >= giu_nr_pins) + return -EBADF; + + if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH) + value = '1'; + + if (len <= 0) + return -EFAULT; + + if (put_user(value, buf)) + return -EFAULT; + + return 1; +} + +static ssize_t gpio_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + unsigned int pin; + size_t i; + char c; + int retval = 0; + + pin = iminor(file->f_dentry->d_inode); + if (pin >= giu_nr_pins) + return -EBADF; + + for (i = 0; i < len; i++) { + if (get_user(c, data + i)) + return -EFAULT; + + switch (c) { + case '0': + retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW); + break; + case '1': + retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH); + break; + case 'D': + printk(KERN_INFO "GPIO%d: pull down\n", pin); + retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN); + break; + case 'd': + printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin); + retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE); + break; + case 'I': + printk(KERN_INFO "GPIO%d: input\n", pin); + retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT); + break; + case 'O': + printk(KERN_INFO "GPIO%d: output\n", pin); + retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT); + break; + case 'o': + printk(KERN_INFO "GPIO%d: output disable\n", pin); + retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE); + break; + case 'P': + printk(KERN_INFO "GPIO%d: pull up\n", pin); + retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP); + break; + case 'p': + printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin); + retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE); + break; + default: + break; + } + + if (retval < 0) + break; + } + + return i; +} + +static int gpio_open(struct inode *inode, struct file *file) +{ + unsigned int pin; + + pin = iminor(inode); + if (pin >= giu_nr_pins) + return -EBADF; + + return nonseekable_open(inode, file); +} + +static int gpio_release(struct inode *inode, struct file *file) +{ + unsigned int pin; + + pin = iminor(inode); + if (pin >= giu_nr_pins) + return -EBADF; + + return 0; +} + +static struct file_operations gpio_fops = { + .owner = THIS_MODULE, + .read = gpio_read, + .write = gpio_write, + .open = gpio_open, + .release = gpio_release, +}; + +static int giu_probe(struct device *dev) +{ + unsigned long start, size, flags = 0; + unsigned int nr_pins = 0; + struct resource *res1, *res2 = NULL; + void *base; + int retval, i; + + switch (current_cpu_data.cputype) { + case CPU_VR4111: + case CPU_VR4121: + start = GIU_TYPE1_START; + size = GIU_TYPE1_SIZE; + flags = GPIO_HAS_PULLUPDOWN_IO; + nr_pins = 50; + break; + case CPU_VR4122: + case CPU_VR4131: + start = GIU_TYPE2_START; + size = GIU_TYPE2_SIZE; + nr_pins = 36; + break; + case CPU_VR4133: + start = GIU_TYPE3_START; + size = GIU_TYPE3_SIZE; + flags = GPIO_HAS_INTERRUPT_EDGE_SELECT; + nr_pins = 48; + break; + default: + return -ENODEV; + } + + res1 = request_mem_region(start, size, "GIU"); + if (res1 == NULL) + return -EBUSY; + + base = ioremap(start, size); + if (base == NULL) { + release_resource(res1); + return -ENOMEM; + } + + if (flags & GPIO_HAS_PULLUPDOWN_IO) { + res2 = request_mem_region(GIU_PULLUPDOWN_START, GIU_PULLUPDOWN_SIZE, "GIU"); + if (res2 == NULL) { + iounmap(base); + release_resource(res1); + return -EBUSY; + } + } + + retval = register_chrdev(major, "GIU", &gpio_fops); + if (retval < 0) { + iounmap(base); + release_resource(res1); + release_resource(res2); + return retval; + } + + if (major == 0) { + major = retval; + printk(KERN_INFO "GIU: major number %d\n", major); + } + + spin_lock_init(&giu_lock); + giu_base = base; + giu_resource1 = res1; + giu_resource2 = res2; + giu_flags = flags; + giu_nr_pins = nr_pins; + + giu_write(GIUINTENL, 0); + giu_write(GIUINTENH, 0); + + for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { + if (i < GIU_IRQ(GIUINT_HIGH_OFFSET)) + irq_desc[i].handler = &giuint_low_irq_type; + else + irq_desc[i].handler = &giuint_high_irq_type; + } + + return cascade_irq(GIUINT_IRQ, giu_get_irq); +} + +static int giu_remove(struct device *dev) +{ + iounmap(giu_base); + + release_resource(giu_resource1); + if (giu_flags & GPIO_HAS_PULLUPDOWN_IO) + release_resource(giu_resource2); + + return 0; +} + +static struct platform_device *giu_platform_device; + +static struct device_driver giu_device_driver = { + .name = "GIU", + .bus = &platform_bus_type, + .probe = giu_probe, + .remove = giu_remove, +}; + +static int __devinit vr41xx_giu_init(void) +{ + int retval; + + giu_platform_device = platform_device_register_simple("GIU", -1, NULL, 0); + if (IS_ERR(giu_platform_device)) + return PTR_ERR(giu_platform_device); + + retval = driver_register(&giu_device_driver); + if (retval < 0) + platform_device_unregister(giu_platform_device); + + return retval; +} + +static void __devexit vr41xx_giu_exit(void) +{ + driver_unregister(&giu_device_driver); + + platform_device_unregister(giu_platform_device); +} + +module_init(vr41xx_giu_init); +module_exit(vr41xx_giu_exit); diff --git a/include/asm-mips/vr41xx/giu.h b/include/asm-mips/vr41xx/giu.h new file mode 100644 index 0000000..8590885 --- /dev/null +++ b/include/asm-mips/vr41xx/giu.h @@ -0,0 +1,69 @@ +/* + * Include file for NEC VR4100 series General-purpose I/O Unit. + * + * Copyright (C) 2005 Yoichi Yuasa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __NEC_VR41XX_GIU_H +#define __NEC_VR41XX_GIU_H + +typedef enum { + IRQ_TRIGGER_LEVEL, + IRQ_TRIGGER_EDGE, + IRQ_TRIGGER_EDGE_FALLING, + IRQ_TRIGGER_EDGE_RISING, +} irq_trigger_t; + +typedef enum { + IRQ_SIGNAL_THROUGH, + IRQ_SIGNAL_HOLD, +} irq_signal_t; + +extern void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal); + +typedef enum { + IRQ_LEVEL_LOW, + IRQ_LEVEL_HIGH, +} irq_level_t; + +extern void vr41xx_set_irq_level(unsigned int pin, irq_level_t level); + +typedef enum { + GPIO_DATA_LOW, + GPIO_DATA_HIGH, + GPIO_DATA_INVAL, +} gpio_data_t; + +extern gpio_data_t vr41xx_gpio_get_pin(unsigned int pin); +extern int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data); + +typedef enum { + GPIO_INPUT, + GPIO_OUTPUT, + GPIO_OUTPUT_DISABLE, +} gpio_direction_t; + +extern int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir); + +typedef enum { + GPIO_PULL_DOWN, + GPIO_PULL_UP, + GPIO_PULL_DISABLE, +} gpio_pull_t; + +extern int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull); + +#endif /* __NEC_VR41XX_GIU_H */ diff --git a/include/asm-mips/vr41xx/vr41xx.h b/include/asm-mips/vr41xx/vr41xx.h index ad0d1ea..7d41e44 100644 --- a/include/asm-mips/vr41xx/vr41xx.h +++ b/include/asm-mips/vr41xx/vr41xx.h @@ -126,7 +126,6 @@ extern void vr41xx_mask_clock(vr41xx_clock_t clock); #define GIU_IRQ_BASE 40 #define GIU_IRQ(x) (GIU_IRQ_BASE + (x)) /* IRQ 40-71 */ #define GIU_IRQ_LAST GIU_IRQ(31) -#define GIU_IRQ_TO_PIN(x) ((x) - GIU_IRQ_BASE) /* Pin 0-31 */ extern int vr41xx_set_intassign(unsigned int irq, unsigned char intassign); extern int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq)); @@ -197,38 +196,4 @@ extern void vr41xx_disable_csiint(uint16_t mask); extern void vr41xx_enable_bcuint(void); extern void vr41xx_disable_bcuint(void); -/* - * General-Purpose I/O Unit - */ -enum { - TRIGGER_LEVEL, - TRIGGER_EDGE, - TRIGGER_EDGE_FALLING, - TRIGGER_EDGE_RISING -}; - -enum { - SIGNAL_THROUGH, - SIGNAL_HOLD -}; - -extern void vr41xx_set_irq_trigger(int pin, int trigger, int hold); - -enum { - LEVEL_LOW, - LEVEL_HIGH -}; - -extern void vr41xx_set_irq_level(int pin, int level); - -enum { - PIO_INPUT, - PIO_OUTPUT -}; - -enum { - DATA_LOW, - DATA_HIGH -}; - #endif /* __NEC_VR41XX_H */ -- cgit v0.10.2 From 22329b511a97557b293583194037d1f4c71e1504 Mon Sep 17 00:00:00 2001 From: Brent Casavant Date: Tue, 21 Jun 2005 17:15:59 -0700 Subject: [PATCH] ioc4: Core driver rewrite This series of patches reworks the configuration and internal structure of the SGI IOC4 I/O controller device drivers. These changes are motivated by several factors: - The IOC4 chip PCI resources are of mixed use between functions (i.e. multiple functions are handled in the same address range, sometimes within the same register), muddling resource ownership and initialization issues. Centralizing this ownership in a core driver is desirable. - The IOC4 chip implements multiple functions (serial, IDE, others not yet implemented in the mainline kernel) but is not a multifunction PCI device. In order to properly handle device addition and removal as well as module insertion and deletion, an intermediary IOC4-specific driver layer is needed to handle these operations cleanly. - All IOC4 drivers are currently enabled by a single CONFIG value. As not all systems need all IOC4 functions, it is desireable to enable these drivers independently. - The current IOC4 core driver will trigger loading of all function-level drivers, as it makes direct calls to them. This situation should be reversed (i.e. function-level drivers cause loading of core driver) in order to maintain a clear and least-surprise driver loading model. - IOC4 hardware design necessitates some driver-level dependency on the PCI bus clock speed. Current code assumes a 66MHz bus, but the speed should be autodetected and appropriate compensation taken. This patch series effects the above changes by a newly and better designed IOC4 core driver with which the function-level drivers can register and deregister themselves upon module insertion/removal. By tracking these modules, device addition/removal is also handled properly. PCI resource management and ownership issues are centralized in this core driver, and IOC4-wide configuration actions such as bus speed detection are also handled in this core driver. This patch: The SGI IOC4 I/O controller chip implements multiple functions, though it is not a multi-function PCI device. Additionally, various PCI resources of the IOC4 are shared by multiple hardware functions, and thus resource ownership by driver is not clearly delineated. Due to the current driver design, all core and subordinate drivers must be loaded, or none, which is undesirable if not all IOC4 hardware features are being used. This patch reorganizes the IOC4 drivers so that the core driver provides a subdriver registration service. Through appropriate callbacks the subdrivers can now handle device addition and removal, as well as module insertion and deletion (though the IOC4 IDE driver requires further work before module deletion will work). The core driver now takes care of allocating PCI resources and data which must be shared between subdrivers, to clearly delineate module ownership of these items. Signed-off-by: Brent Casavant Acked-by: Pat Gefre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/sgi-ioc4.txt b/Documentation/sgi-ioc4.txt new file mode 100644 index 0000000..876c96a --- /dev/null +++ b/Documentation/sgi-ioc4.txt @@ -0,0 +1,45 @@ +The SGI IOC4 PCI device is a bit of a strange beast, so some notes on +it are in order. + +First, even though the IOC4 performs multiple functions, such as an +IDE controller, a serial controller, a PS/2 keyboard/mouse controller, +and an external interrupt mechanism, it's not implemented as a +multifunction device. The consequence of this from a software +standpoint is that all these functions share a single IRQ, and +they can't all register to own the same PCI device ID. To make +matters a bit worse, some of the register blocks (and even registers +themselves) present in IOC4 are mixed-purpose between these several +functions, meaning that there's no clear "owning" device driver. + +The solution is to organize the IOC4 driver into several independent +drivers, "ioc4", "sgiioc4", and "ioc4_serial". Note that there is no +PS/2 controller driver as this functionality has never been wired up +on a shipping IO card. + +ioc4 +==== +This is the core (or shim) driver for IOC4. It is responsible for +initializing the basic functionality of the chip, and allocating +the PCI resources that are shared between the IOC4 functions. + +This driver also provides registration functions that the other +IOC4 drivers can call to make their presence known. Each driver +needs to provide a probe and remove function, which are invoked +by the core driver at appropriate times. The interface of these +IOC4 function probe and remove operations isn't precisely the same +as PCI device probe and remove operations, but is logically the +same operation. + +sgiioc4 +======= +This is the IDE driver for IOC4. Its name isn't very descriptive +simply for historical reasons (it used to be the only IOC4 driver +component). There's not much to say about it other than it hooks +up to the ioc4 driver via the appropriate registration, probe, and +remove functions. + +ioc4_serial +=========== +This is the serial driver for IOC4. There's not much to say about it +other than it hooks up to the ioc4 driver via the appropriate registration, +probe, and remove functions. diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 4651a22..af526b6 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -715,14 +715,34 @@ static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = { }; int -ioc4_ide_attach_one(struct pci_dev *dev, const struct pci_device_id *id) +ioc4_ide_attach_one(struct ioc4_driver_data *idd) { - return pci_init_sgiioc4(dev, &sgiioc4_chipsets[id->driver_data]); + return pci_init_sgiioc4(idd->idd_pdev, + &sgiioc4_chipsets[idd->idd_pci_id->driver_data]); } +static struct ioc4_submodule ioc4_ide_submodule = { + .is_name = "IOC4_ide", + .is_owner = THIS_MODULE, + .is_probe = ioc4_ide_attach_one, +/* .is_remove = ioc4_ide_remove_one, */ +}; + +static int __devinit +ioc4_ide_init(void) +{ + return ioc4_register_submodule(&ioc4_ide_submodule); +} + +static void __devexit +ioc4_ide_exit(void) +{ + ioc4_unregister_submodule(&ioc4_ide_submodule); +} + +module_init(ioc4_ide_init); +module_exit(ioc4_ide_exit); MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)"); MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(ioc4_ide_attach_one); diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index ba4e13a..da5f10e 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include /* @@ -130,12 +130,19 @@ IOC4_SIO_IR_S3_TX_EXPLICIT) /* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */ -#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ -#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ -#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ -#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ -#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ -#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ +#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ +#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ +#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ +#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ +#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ +#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ +#define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Keyboard/mouse */ +#define IOC4_OTHER_IR_RESERVED 0x007fff80 /* Reserved */ +#define IOC4_OTHER_IR_RT_INT 0x00800000 /* INT_OUT section output */ +#define IOC4_OTHER_IR_GEN_INT 0xff000000 /* Generic pins */ + +#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \ + IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR) /* Bitmasks for IOC4_SIO_CR */ #define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 /* byte bus strobe shift */ @@ -274,67 +281,22 @@ struct ioc4_uartregs { #define i4u_dlm u2.dlm #define i4u_fcr u3.fcr -/* PCI memory space register map addressed using pci_bar0 */ -struct ioc4_memregs { - struct ioc4_mem { - /* Miscellaneous IOC4 registers */ - uint32_t pci_err_addr_l; - uint32_t pci_err_addr_h; - uint32_t sio_ir; - uint32_t other_ir; - - /* These registers are read-only for general kernel code. */ - uint32_t sio_ies_ro; - uint32_t other_ies_ro; - uint32_t sio_iec_ro; - uint32_t other_iec_ro; - uint32_t sio_cr; - uint32_t misc_fill1; - uint32_t int_out; - uint32_t misc_fill2; - uint32_t gpcr_s; - uint32_t gpcr_c; - uint32_t gpdr; - uint32_t misc_fill3; - uint32_t gppr_0; - uint32_t gppr_1; - uint32_t gppr_2; - uint32_t gppr_3; - uint32_t gppr_4; - uint32_t gppr_5; - uint32_t gppr_6; - uint32_t gppr_7; - } ioc4_mem; - - char misc_fill4[0x100 - 0x5C - 4]; - - /* ATA/ATAP registers */ - uint32_t ata_notused[9]; - char ata_fill1[0x140 - 0x120 - 4]; - uint32_t ata_notused1[8]; - char ata_fill2[0x200 - 0x15C - 4]; - - /* Keyboard and mouse registers */ - uint32_t km_notused[5];; - char km_fill1[0x300 - 0x210 - 4]; - - /* Serial port registers used for DMA serial I/O */ - struct ioc4_serial { - uint32_t sbbr01_l; - uint32_t sbbr01_h; - uint32_t sbbr23_l; - uint32_t sbbr23_h; - - struct ioc4_serialregs port_0; - struct ioc4_serialregs port_1; - struct ioc4_serialregs port_2; - struct ioc4_serialregs port_3; - struct ioc4_uartregs uart_0; - struct ioc4_uartregs uart_1; - struct ioc4_uartregs uart_2; - struct ioc4_uartregs uart_3; - } ioc4_serial; -}; +/* Serial port registers used for DMA serial I/O */ +struct ioc4_serial { + uint32_t sbbr01_l; + uint32_t sbbr01_h; + uint32_t sbbr23_l; + uint32_t sbbr23_h; + + struct ioc4_serialregs port_0; + struct ioc4_serialregs port_1; + struct ioc4_serialregs port_2; + struct ioc4_serialregs port_3; + struct ioc4_uartregs uart_0; + struct ioc4_uartregs uart_1; + struct ioc4_uartregs uart_2; + struct ioc4_uartregs uart_3; +} ioc4_serial; /* UART clock speed */ #define IOC4_SER_XIN_CLK IOC4_SER_XIN_CLK_66 @@ -412,8 +374,8 @@ enum sio_proto { | UART_LCR_WLEN7 | UART_LCR_WLEN8) #define LCR_MASK_STOP_BITS (UART_LCR_STOP) -#define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir) & _p->ip_ienb) -#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir) +#define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb) +#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw) /* Default to 4k buffers */ #ifdef IOC4_1K_BUFFERS @@ -447,7 +409,7 @@ struct ioc4_control { */ #define MAX_IOC4_INTR_ENTS (8 * sizeof(uint32_t)) struct ioc4_soft { - struct ioc4_mem __iomem *is_ioc4_mem_addr; + struct ioc4_misc_regs __iomem *is_ioc4_misc_addr; struct ioc4_serial __iomem *is_ioc4_serial_addr; /* Each interrupt type has an entry in the array */ @@ -486,7 +448,7 @@ struct ioc4_port { struct ioc4_soft *ip_ioc4_soft; /* pci mem addresses */ - struct ioc4_mem __iomem *ip_mem; + struct ioc4_misc_regs __iomem *ip_mem; struct ioc4_serial __iomem *ip_serial; struct ioc4_serialregs __iomem *ip_serial_regs; struct ioc4_uartregs __iomem *ip_uart_regs; @@ -553,7 +515,7 @@ struct hooks { uint32_t intr_dma_error; uint32_t intr_clear; uint32_t intr_all; - char rs422_select_pin; + int rs422_select_pin; }; static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = { @@ -669,7 +631,7 @@ static void handle_intr(void *arg, uint32_t sio_ir); static inline void write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) { - struct ioc4_mem __iomem *mem = ioc4_soft->is_ioc4_mem_addr; + struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr; unsigned long flags; spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags); @@ -678,11 +640,11 @@ write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) case IOC4_SIO_INTR_TYPE: switch (which) { case IOC4_W_IES: - writel(val, &mem->sio_ies_ro); + writel(val, &mem->sio_ies.raw); break; case IOC4_W_IEC: - writel(val, &mem->sio_iec_ro); + writel(val, &mem->sio_iec.raw); break; } break; @@ -690,11 +652,11 @@ write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) case IOC4_OTHER_INTR_TYPE: switch (which) { case IOC4_W_IES: - writel(val, &mem->other_ies_ro); + writel(val, &mem->other_ies.raw); break; case IOC4_W_IEC: - writel(val, &mem->other_iec_ro); + writel(val, &mem->other_iec.raw); break; } break; @@ -747,7 +709,8 @@ static int set_baud(struct ioc4_port *port, int baud) */ static struct ioc4_port *get_ioc4_port(struct uart_port *the_port) { - struct ioc4_control *control = dev_get_drvdata(the_port->dev); + struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev); + struct ioc4_control *control = idd->idd_serial_data; int ii; if (control) { @@ -782,7 +745,7 @@ static struct ioc4_port *get_ioc4_port(struct uart_port *the_port) static inline uint32_t pending_intrs(struct ioc4_soft *soft, int type) { - struct ioc4_mem __iomem *mem = soft->is_ioc4_mem_addr; + struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; unsigned long flag; uint32_t intrs = 0; @@ -793,11 +756,11 @@ pending_intrs(struct ioc4_soft *soft, int type) switch (type) { case IOC4_SIO_INTR_TYPE: - intrs = readl(&mem->sio_ir) & readl(&mem->sio_ies_ro); + intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw); break; case IOC4_OTHER_INTR_TYPE: - intrs = readl(&mem->other_ir) & readl(&mem->other_ies_ro); + intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw); /* Don't process any ATA interrupte */ intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); @@ -826,7 +789,7 @@ static int inline port_init(struct ioc4_port *port) /* Wait until any pending bus activity for this port has ceased */ do - sio_cr = readl(&port->ip_mem->sio_cr); + sio_cr = readl(&port->ip_mem->sio_cr.raw); while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE)); /* Finish reset sequence */ @@ -899,7 +862,7 @@ static int inline port_init(struct ioc4_port *port) write_ireg(port->ip_ioc4_soft, hooks->intr_clear, IOC4_W_IEC, IOC4_SIO_INTR_TYPE); port->ip_ienb &= ~hooks->intr_clear; - writel(hooks->intr_clear, &port->ip_mem->sio_ir); + writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw); return 0; } @@ -918,23 +881,23 @@ static void handle_dma_error_intr(void *arg, uint32_t other_ir) spin_lock_irqsave(&port->ip_lock, flags); /* ACK the interrupt */ - writel(hooks->intr_dma_error, &port->ip_mem->other_ir); + writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw); - if (readl(&port->ip_mem->pci_err_addr_l) & IOC4_PCI_ERR_ADDR_VLD) { + if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) { printk(KERN_ERR "PCI error address is 0x%lx, " "master is serial port %c %s\n", (((uint64_t)readl(&port->ip_mem->pci_err_addr_h) << 32) - | readl(&port->ip_mem->pci_err_addr_l)) + | readl(&port->ip_mem->pci_err_addr_l.raw)) & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' + - ((char)(readl(&port->ip_mem-> pci_err_addr_l) & + ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1), - (readl(&port->ip_mem->pci_err_addr_l) + (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_MST_TYP_MSK) ? "RX" : "TX"); - if (readl(&port->ip_mem->pci_err_addr_l) + if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_MUL_ERR) { printk(KERN_ERR "Multiple errors occurred\n"); @@ -1018,26 +981,26 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) "other_ies = 0x%x\n", (intr_type == IOC4_SIO_INTR_TYPE) ? "sio" : "other", this_ir, - readl(&soft->is_ioc4_mem_addr->sio_ir), - readl(&soft->is_ioc4_mem_addr->sio_ies_ro), - readl(&soft->is_ioc4_mem_addr->other_ir), - readl(&soft->is_ioc4_mem_addr->other_ies_ro)); + readl(&soft->is_ioc4_misc_addr->sio_ir.raw), + readl(&soft->is_ioc4_misc_addr->sio_ies.raw), + readl(&soft->is_ioc4_misc_addr->other_ir.raw), + readl(&soft->is_ioc4_misc_addr->other_ies.raw)); } } #ifdef DEBUG_INTERRUPTS { - struct ioc4_mem __iomem *mem = soft->is_ioc4_mem_addr; + struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; spinlock_t *lp = &soft->is_ir_lock; unsigned long flag; spin_lock_irqsave(&soft->is_ir_lock, flag); - printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies_ro 0x%x " - "other_ir 0x%x other_ies_ro 0x%x mask 0x%x\n", + printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x " + "other_ir 0x%x other_ies 0x%x mask 0x%x\n", __FUNCTION__, __LINE__, - (void *)mem, readl(&mem->sio_ir), - readl(&mem->sio_ies_ro), - readl(&mem->other_ir), - readl(&mem->other_ies_ro), + (void *)mem, readl(&mem->sio_ir.raw), + readl(&mem->sio_ies.raw), + readl(&mem->other_ir.raw), + readl(&mem->other_ies.raw), IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); spin_unlock_irqrestore(&soft->is_ir_lock, flag); } @@ -1056,7 +1019,7 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) */ static int inline ioc4_attach_local(struct pci_dev *pdev, struct ioc4_control *control, - struct ioc4_soft *soft, void __iomem *ioc4_mem, + struct ioc4_soft *soft, void __iomem *ioc4_misc, void __iomem *ioc4_serial) { struct ioc4_port *port; @@ -1076,7 +1039,7 @@ static int inline ioc4_attach_local(struct pci_dev *pdev, ioc4_revid, ioc4_revid_min); return -EPERM; } - BUG_ON(ioc4_mem == NULL); + BUG_ON(ioc4_misc == NULL); BUG_ON(ioc4_serial == NULL); /* Create port structures for each port */ @@ -1103,7 +1066,7 @@ static int inline ioc4_attach_local(struct pci_dev *pdev, port->ip_pci_bus_speed = IOC4_SER_XIN_CLK; port->ip_baud = 9600; port->ip_control = control; - port->ip_mem = ioc4_mem; + port->ip_mem = ioc4_misc; port->ip_serial = ioc4_serial; /* point to the right hook */ @@ -1604,14 +1567,12 @@ static int ioc4_set_proto(struct ioc4_port *port, enum sio_proto proto) switch (proto) { case PROTO_RS232: /* Clear the appropriate GIO pin */ - writel(0, (&port->ip_mem->gppr_0 + - hooks->rs422_select_pin)); + writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw)); break; case PROTO_RS422: /* Set the appropriate GIO pin */ - writel(1, (&port->ip_mem->gppr_0 + - hooks->rs422_select_pin)); + writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw)); break; default: @@ -1885,7 +1846,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) if (sio_ir & hooks->intr_delta_dcd) { /* ACK the interrupt */ writel(hooks->intr_delta_dcd, - &port->ip_mem->sio_ir); + &port->ip_mem->sio_ir.raw); shadow = readl(&port->ip_serial_regs->shadow); @@ -1907,7 +1868,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) if (sio_ir & hooks->intr_delta_cts) { /* ACK the interrupt */ writel(hooks->intr_delta_cts, - &port->ip_mem->sio_ir); + &port->ip_mem->sio_ir.raw); shadow = readl(&port->ip_serial_regs->shadow); @@ -1928,7 +1889,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) if (sio_ir & hooks->intr_rx_timer) { /* ACK the interrupt */ writel(hooks->intr_rx_timer, - &port->ip_mem->sio_ir); + &port->ip_mem->sio_ir.raw); if ((port->ip_notify & N_DATA_READY) && (port->ip_port)) { @@ -1974,7 +1935,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) /* ACK the interrupt */ writel(hooks->intr_tx_explicit, - &port->ip_mem->sio_ir); + &port->ip_mem->sio_ir.raw); if (port->ip_notify & N_OUTPUT_LOWAT) ioc4_cb_output_lowat(port); @@ -2634,7 +2595,8 @@ ioc4_serial_core_attach(struct pci_dev *pdev) { struct ioc4_port *port; struct uart_port *the_port; - struct ioc4_control *control = pci_get_drvdata(pdev); + struct ioc4_driver_data *idd = pci_get_drvdata(pdev); + struct ioc4_control *control = idd->idd_serial_data; int ii; DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n", @@ -2680,55 +2642,29 @@ ioc4_serial_core_attach(struct pci_dev *pdev) /** * ioc4_serial_attach_one - register attach function - * called per card found from ioc4_serial_detect as part - * of module_init(). - * @pdev: handle for this card - * @pci_id: pci id for this card + * called per card found from IOC4 master module. + * @idd: Master module data for this IOC4 */ int -ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) +ioc4_serial_attach_one(struct ioc4_driver_data *idd) { - struct ioc4_mem __iomem *mem; - unsigned long tmp_addr, tmp_addr1; + unsigned long tmp_addr1; struct ioc4_serial __iomem *serial; struct ioc4_soft *soft; struct ioc4_control *control; - int tmp, ret = 0; + int ret = 0; - DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, pdev, pci_id)); - - /* Map in the ioc4 memory */ - tmp_addr = pci_resource_start(pdev, 0); - if (!tmp_addr) { - printk(KERN_WARNING - "ioc4 (%p) : unable to get PIO mapping for " - "MEM space\n", (void *)pdev); - return -ENODEV; - } - if (!request_region(tmp_addr, sizeof(struct ioc4_mem), "sioc4_mem")) { - printk(KERN_ALERT - "ioc4 (%p): unable to get request region for " - "MEM space\n", (void *)pdev); - return -ENODEV; - } - mem = ioremap(tmp_addr, sizeof(struct ioc4_mem)); - if (!mem) { - printk(KERN_WARNING - "ioc4 (%p) : unable to remap ioc4 memory\n", - (void *)pdev); - ret = -ENODEV; - goto out1; - } + DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev, idd->idd_pci_id)); /* request serial registers */ - tmp_addr1 = pci_resource_start(pdev, 0) + IOC4_SERIAL_OFFSET; + tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET; if (!request_region(tmp_addr1, sizeof(struct ioc4_serial), "sioc4_uart")) { printk(KERN_WARNING "ioc4 (%p): unable to get request region for " - "uart space\n", (void *)pdev); + "uart space\n", (void *)idd->idd_pdev); ret = -ENODEV; goto out1; } @@ -2736,12 +2672,12 @@ ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) if (!serial) { printk(KERN_WARNING "ioc4 (%p) : unable to remap ioc4 serial register\n", - (void *)pdev); + (void *)idd->idd_pdev); ret = -ENODEV; goto out2; } DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n", - __FUNCTION__, (void *)mem, (void *)serial)); + __FUNCTION__, (void *)idd->idd_misc_regs, (void *)serial)); /* Get memory for the new card */ control = kmalloc(sizeof(struct ioc4_control) * IOC4_NUM_SERIAL_PORTS, @@ -2754,59 +2690,57 @@ ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) goto out2; } memset(control, 0, sizeof(struct ioc4_control)); - pci_set_drvdata(pdev, control); + idd->idd_serial_data = control; /* Allocate the soft structure */ soft = kmalloc(sizeof(struct ioc4_soft), GFP_KERNEL); if (!soft) { printk(KERN_WARNING "ioc4 (%p): unable to get memory for the soft struct\n", - (void *)pdev); + (void *)idd->idd_pdev); ret = -ENOMEM; goto out3; } memset(soft, 0, sizeof(struct ioc4_soft)); spin_lock_init(&soft->is_ir_lock); - soft->is_ioc4_mem_addr = mem; + soft->is_ioc4_misc_addr = idd->idd_misc_regs; soft->is_ioc4_serial_addr = serial; /* Init the IOC4 */ - pci_read_config_dword(pdev, PCI_COMMAND, &tmp); - pci_write_config_dword(pdev, PCI_COMMAND, - tmp | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); - - writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT, &mem->sio_cr); + writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT, + &idd->idd_misc_regs->sio_cr.raw); /* Enable serial port mode select generic PIO pins as outputs */ writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL, - &mem->gpcr_s); + &idd->idd_misc_regs->gpcr_s.raw); - /* Clear and disable all interrupts */ + /* Clear and disable all serial interrupts */ write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE); - writel(~0, &mem->sio_ir); - write_ireg(soft, ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR), - IOC4_W_IEC, IOC4_OTHER_INTR_TYPE); - writel(~(IOC4_OTHER_IR_ATA_MEMERR | IOC4_OTHER_IR_ATA_MEMERR), - &mem->other_ir); + writel(~0, &idd->idd_misc_regs->sio_ir.raw); + write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC, + IOC4_OTHER_INTR_TYPE); + writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw); control->ic_soft = soft; - if (!request_irq(pdev->irq, ioc4_intr, SA_SHIRQ, + + /* Hook up interrupt handler */ + if (!request_irq(idd->idd_pdev->irq, ioc4_intr, SA_SHIRQ, "sgi-ioc4serial", (void *)soft)) { - control->ic_irq = pdev->irq; + control->ic_irq = idd->idd_pdev->irq; } else { printk(KERN_WARNING "%s : request_irq fails for IRQ 0x%x\n ", - __FUNCTION__, pdev->irq); + __FUNCTION__, idd->idd_pdev->irq); } - if ((ret = ioc4_attach_local(pdev, control, soft, - soft->is_ioc4_mem_addr, + if ((ret = ioc4_attach_local(idd->idd_pdev, control, soft, + soft->is_ioc4_misc_addr, soft->is_ioc4_serial_addr))) goto out4; /* register port with the serial core */ - if ((ret = ioc4_serial_core_attach(pdev))) + if ((ret = ioc4_serial_core_attach(idd->idd_pdev))) goto out4; return ret; @@ -2819,7 +2753,6 @@ out3: out2: release_region(tmp_addr1, sizeof(struct ioc4_serial)); out1: - release_region(tmp_addr, sizeof(struct ioc4_mem)); return ret; } @@ -2828,11 +2761,10 @@ out1: /** * ioc4_serial_remove_one - detach function * - * @pdev: handle for this card + * @idd: IOC4 master module data for this IOC4 */ -#if 0 -void ioc4_serial_remove_one(struct pci_dev *pdev) +int ioc4_serial_remove_one(struct ioc4_driver_data *idd) { int ii; struct ioc4_control *control; @@ -2840,7 +2772,7 @@ void ioc4_serial_remove_one(struct pci_dev *pdev) struct ioc4_port *port; struct ioc4_soft *soft; - control = pci_get_drvdata(pdev); + control = idd->idd_serial_data; for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) { the_port = &control->ic_port[ii].icp_uart_port; @@ -2867,10 +2799,17 @@ void ioc4_serial_remove_one(struct pci_dev *pdev) kfree(soft); } kfree(control); - pci_set_drvdata(pdev, NULL); - uart_unregister_driver(&ioc4_uart); + idd->idd_serial_data = NULL; + + return 0; } -#endif + +static struct ioc4_submodule ioc4_serial_submodule = { + .is_name = "IOC4_serial", + .is_owner = THIS_MODULE, + .is_probe = ioc4_serial_attach_one, + .is_remove = ioc4_serial_remove_one, +}; /** * ioc4_serial_init - module init @@ -2886,12 +2825,20 @@ int ioc4_serial_init(void) __FUNCTION__); return ret; } - return 0; + + /* register with IOC4 main module */ + return ioc4_register_submodule(&ioc4_serial_submodule); } +static void __devexit ioc4_serial_exit(void) +{ + ioc4_unregister_submodule(&ioc4_serial_submodule); + uart_unregister_driver(&ioc4_uart); +} + +module_init(ioc4_serial_init); +module_exit(ioc4_serial_exit); + MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) "); MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(ioc4_serial_init); -EXPORT_SYMBOL(ioc4_serial_attach_one); diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c index d9e4ee2..70862d7 100644 --- a/drivers/sn/ioc4.c +++ b/drivers/sn/ioc4.c @@ -6,60 +6,294 @@ * Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved. */ -/* - * This file contains a shim driver for the IOC4 IDE and serial drivers. +/* This file contains the master driver module for use by SGI IOC4 subdrivers. + * + * It allocates any resources shared between multiple subdevices, and + * provides accessor functions (where needed) and the like for those + * resources. It also provides a mechanism for the subdevice modules + * to support loading and unloading. + * + * Non-shared resources (e.g. external interrupt A_INT_OUT register page + * alias, serial port and UART registers) are handled by the subdevice + * modules themselves. + * + * This is all necessary because IOC4 is not implemented as a multi-function + * PCI device, but an amalgamation of disparate registers for several + * types of device (ATA, serial, external interrupts). The normal + * resource management in the kernel doesn't have quite the right interfaces + * to handle this situation (e.g. multiple modules can't claim the same + * PCI ID), thus this IOC4 master module. */ #include #include #include -#include -#include +#include +#include +/************************ + * Submodule management * + ************************/ -static int __devinit -ioc4_probe_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) +static LIST_HEAD(ioc4_devices); +static DECLARE_RWSEM(ioc4_devices_rwsem); + +static LIST_HEAD(ioc4_submodules); +static DECLARE_RWSEM(ioc4_submodules_rwsem); + +/* Register an IOC4 submodule */ +int +ioc4_register_submodule(struct ioc4_submodule *is) +{ + struct ioc4_driver_data *idd; + + down_write(&ioc4_submodules_rwsem); + list_add(&is->is_list, &ioc4_submodules); + up_write(&ioc4_submodules_rwsem); + + /* Initialize submodule for each IOC4 */ + if (!is->is_probe) + return 0; + + down_read(&ioc4_devices_rwsem); + list_for_each_entry(idd, &ioc4_devices, idd_list) { + if (is->is_probe(idd)) { + printk(KERN_WARNING + "%s: IOC4 submodule %s probe failed " + "for pci_dev %s", + __FUNCTION__, module_name(is->is_owner), + pci_name(idd->idd_pdev)); + } + } + up_read(&ioc4_devices_rwsem); + + return 0; +} + +/* Unregister an IOC4 submodule */ +void +ioc4_unregister_submodule(struct ioc4_submodule *is) { + struct ioc4_driver_data *idd; + + down_write(&ioc4_submodules_rwsem); + list_del(&is->is_list); + up_write(&ioc4_submodules_rwsem); + + /* Remove submodule for each IOC4 */ + if (!is->is_remove) + return; + + down_read(&ioc4_devices_rwsem); + list_for_each_entry(idd, &ioc4_devices, idd_list) { + if (is->is_remove(idd)) { + printk(KERN_WARNING + "%s: IOC4 submodule %s remove failed " + "for pci_dev %s.\n", + __FUNCTION__, module_name(is->is_owner), + pci_name(idd->idd_pdev)); + } + } + up_read(&ioc4_devices_rwsem); +} + +/********************* + * Device management * + *********************/ + +/* Adds a new instance of an IOC4 card */ +static int +ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +{ + struct ioc4_driver_data *idd; + struct ioc4_submodule *is; + uint32_t pcmd; int ret; + /* Enable IOC4 and take ownership of it */ if ((ret = pci_enable_device(pdev))) { printk(KERN_WARNING - "%s: Failed to enable device with " - "pci_dev 0x%p... returning\n", - __FUNCTION__, (void *)pdev); - return ret; + "%s: Failed to enable IOC4 device for pci_dev %s.\n", + __FUNCTION__, pci_name(pdev)); + goto out; } pci_set_master(pdev); - /* attach each sub-device */ - ret = ioc4_ide_attach_one(pdev, pci_id); - if (ret) - return ret; - return ioc4_serial_attach_one(pdev, pci_id); + /* Set up per-IOC4 data */ + idd = kmalloc(sizeof(struct ioc4_driver_data), GFP_KERNEL); + if (!idd) { + printk(KERN_WARNING + "%s: Failed to allocate IOC4 data for pci_dev %s.\n", + __FUNCTION__, pci_name(pdev)); + ret = -ENODEV; + goto out_idd; + } + idd->idd_pdev = pdev; + idd->idd_pci_id = pci_id; + + /* Map IOC4 misc registers. These are shared between subdevices + * so the main IOC4 module manages them. + */ + idd->idd_bar0 = pci_resource_start(idd->idd_pdev, 0); + if (!idd->idd_bar0) { + printk(KERN_WARNING + "%s: Unable to find IOC4 misc resource " + "for pci_dev %s.\n", + __FUNCTION__, pci_name(idd->idd_pdev)); + ret = -ENODEV; + goto out_pci; + } + if (!request_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs), + "ioc4_misc")) { + printk(KERN_WARNING + "%s: Unable to request IOC4 misc region " + "for pci_dev %s.\n", + __FUNCTION__, pci_name(idd->idd_pdev)); + ret = -ENODEV; + goto out_pci; + } + idd->idd_misc_regs = ioremap(idd->idd_bar0, + sizeof(struct ioc4_misc_regs)); + if (!idd->idd_misc_regs) { + printk(KERN_WARNING + "%s: Unable to remap IOC4 misc region " + "for pci_dev %s.\n", + __FUNCTION__, pci_name(idd->idd_pdev)); + ret = -ENODEV; + goto out_misc_region; + } + + /* Failsafe portion of per-IOC4 initialization */ + + /* Initialize IOC4 */ + pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd); + pci_write_config_dword(idd->idd_pdev, PCI_COMMAND, + pcmd | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); + + /* Disable/clear all interrupts. Need to do this here lest + * one submodule request the shared IOC4 IRQ, but interrupt + * is generated by a different subdevice. + */ + /* Disable */ + writel(~0, &idd->idd_misc_regs->other_iec.raw); + writel(~0, &idd->idd_misc_regs->sio_iec); + /* Clear (i.e. acknowledge) */ + writel(~0, &idd->idd_misc_regs->other_ir.raw); + writel(~0, &idd->idd_misc_regs->sio_ir); + + /* Track PCI-device specific data */ + idd->idd_serial_data = NULL; + pci_set_drvdata(idd->idd_pdev, idd); + down_write(&ioc4_devices_rwsem); + list_add(&idd->idd_list, &ioc4_devices); + up_write(&ioc4_devices_rwsem); + + /* Add this IOC4 to all submodules */ + down_read(&ioc4_submodules_rwsem); + list_for_each_entry(is, &ioc4_submodules, is_list) { + if (is->is_probe && is->is_probe(idd)) { + printk(KERN_WARNING + "%s: IOC4 submodule 0x%s probe failed " + "for pci_dev %s.\n", + __FUNCTION__, module_name(is->is_owner), + pci_name(idd->idd_pdev)); + } + } + up_read(&ioc4_submodules_rwsem); + + return 0; + +out_misc_region: + release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); +out_pci: + kfree(idd); +out_idd: + pci_disable_device(pdev); +out: + return ret; } -/* pci device struct */ -static struct pci_device_id ioc4_s_id_table[] = { +/* Removes a particular instance of an IOC4 card. */ +static void +ioc4_remove(struct pci_dev *pdev) +{ + struct ioc4_submodule *is; + struct ioc4_driver_data *idd; + + idd = pci_get_drvdata(pdev); + + /* Remove this IOC4 from all submodules */ + down_read(&ioc4_submodules_rwsem); + list_for_each_entry(is, &ioc4_submodules, is_list) { + if (is->is_remove && is->is_remove(idd)) { + printk(KERN_WARNING + "%s: IOC4 submodule 0x%s remove failed " + "for pci_dev %s.\n", + __FUNCTION__, module_name(is->is_owner), + pci_name(idd->idd_pdev)); + } + } + up_read(&ioc4_submodules_rwsem); + + /* Release resources */ + iounmap(idd->idd_misc_regs); + if (!idd->idd_bar0) { + printk(KERN_WARNING + "%s: Unable to get IOC4 misc mapping for pci_dev %s. " + "Device removal may be incomplete.\n", + __FUNCTION__, pci_name(idd->idd_pdev)); + } + release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); + + /* Disable IOC4 and relinquish */ + pci_disable_device(pdev); + + /* Remove and free driver data */ + down_write(&ioc4_devices_rwsem); + list_del(&idd->idd_list); + up_write(&ioc4_devices_rwsem); + kfree(idd); +} + +static struct pci_device_id ioc4_id_table[] = { {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID, PCI_ANY_ID, 0x0b4000, 0xFFFFFF}, {0} }; -MODULE_DEVICE_TABLE(pci, ioc4_s_id_table); -static struct pci_driver __devinitdata ioc4_s_driver = { - .name = "IOC4", - .id_table = ioc4_s_id_table, - .probe = ioc4_probe_one, +static struct pci_driver __devinitdata ioc4_driver = { + .name = "IOC4", + .id_table = ioc4_id_table, + .probe = ioc4_probe, + .remove = ioc4_remove, }; -static int __devinit ioc4_detect(void) +MODULE_DEVICE_TABLE(pci, ioc4_id_table); + +/********************* + * Module management * + *********************/ + +/* Module load */ +static int __devinit +ioc4_init(void) { - ioc4_serial_init(); + return pci_register_driver(&ioc4_driver); +} - return pci_register_driver(&ioc4_s_driver); +/* Module unload */ +static void __devexit +ioc4_exit(void) +{ + pci_unregister_driver(&ioc4_driver); } -module_init(ioc4_detect); -MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) "); -MODULE_DESCRIPTION("PCI driver module for SGI IOC4 Base-IO Card"); +module_init(ioc4_init); +module_exit(ioc4_exit); + +MODULE_AUTHOR("Brent Casavant - Silicon Graphics, Inc. "); +MODULE_DESCRIPTION("PCI driver master module for SGI IOC4 Base-IO Card"); MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(ioc4_register_submodule); +EXPORT_SYMBOL(ioc4_unregister_submodule); diff --git a/include/linux/ioc4.h b/include/linux/ioc4.h new file mode 100644 index 0000000..729bfa4 --- /dev/null +++ b/include/linux/ioc4.h @@ -0,0 +1,156 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. + */ + +#ifndef _LINUX_IOC4_H +#define _LINUX_IOC4_H + +#include + +/*********************************** + * Structures needed by subdrivers * + ***********************************/ + +/* This structure fully describes the IOC4 miscellaneous registers which + * appear at bar[0]+0x00000 through bar[0]+0x0005c. The corresponding + * PCI resource is managed by the main IOC4 driver because it contains + * registers of interest to many different IOC4 subdrivers. + */ +struct ioc4_misc_regs { + /* Miscellaneous IOC4 registers */ + union ioc4_pci_err_addr_l { + uint32_t raw; + struct { + uint32_t valid:1; /* Address captured */ + uint32_t master_id:4; /* Unit causing error + * 0/1: Serial port 0 TX/RX + * 2/3: Serial port 1 TX/RX + * 4/5: Serial port 2 TX/RX + * 6/7: Serial port 3 TX/RX + * 8: ATA/ATAPI + * 9-15: Undefined + */ + uint32_t mul_err:1; /* Multiple errors occurred */ + uint32_t addr:26; /* Bits 31-6 of error addr */ + } fields; + } pci_err_addr_l; + uint32_t pci_err_addr_h; /* Bits 63-32 of error addr */ + union ioc4_sio_int { + uint32_t raw; + struct { + uint8_t tx_mt:1; /* TX ring buffer empty */ + uint8_t rx_full:1; /* RX ring buffer full */ + uint8_t rx_high:1; /* RX high-water exceeded */ + uint8_t rx_timer:1; /* RX timer has triggered */ + uint8_t delta_dcd:1; /* DELTA_DCD seen */ + uint8_t delta_cts:1; /* DELTA_CTS seen */ + uint8_t intr_pass:1; /* Interrupt pass-through */ + uint8_t tx_explicit:1; /* TX, MCW, or delay complete */ + } fields[4]; + } sio_ir; /* Serial interrupt state */ + union ioc4_other_int { + uint32_t raw; + struct { + uint32_t ata_int:1; /* ATA port passthru */ + uint32_t ata_memerr:1; /* ATA halted by mem error */ + uint32_t memerr:4; /* Serial halted by mem err */ + uint32_t kbd_int:1; /* kbd/mouse intr asserted */ + uint32_t reserved:16; /* zero */ + uint32_t rt_int:1; /* INT_OUT section latch */ + uint32_t gen_int:8; /* Intr. from generic pins */ + } fields; + } other_ir; /* Other interrupt state */ + union ioc4_sio_int sio_ies; /* Serial interrupt enable set */ + union ioc4_other_int other_ies; /* Other interrupt enable set */ + union ioc4_sio_int sio_iec; /* Serial interrupt enable clear */ + union ioc4_other_int other_iec; /* Other interrupt enable clear */ + union ioc4_sio_cr { + uint32_t raw; + struct { + uint32_t cmd_pulse:4; /* Bytebus strobe width */ + uint32_t arb_diag:3; /* PCI bus requester */ + uint32_t sio_diag_idle:1; /* Active ser req? */ + uint32_t ata_diag_idle:1; /* Active ATA req? */ + uint32_t ata_diag_active:1; /* ATA req is winner */ + uint32_t reserved:22; /* zero */ + } fields; + } sio_cr; + uint32_t unused1; + union ioc4_int_out { + uint32_t raw; + struct { + uint32_t count:16; /* Period control */ + uint32_t mode:3; /* Output signal shape */ + uint32_t reserved:11; /* zero */ + uint32_t diag:1; /* Timebase control */ + uint32_t int_out:1; /* Current value */ + } fields; + } int_out; /* External interrupt output control */ + uint32_t unused2; + union ioc4_gpcr { + uint32_t raw; + struct { + uint32_t dir:8; /* Pin direction */ + uint32_t edge:8; /* Edge/level mode */ + uint32_t reserved1:4; /* zero */ + uint32_t int_out_en:1; /* INT_OUT enable */ + uint32_t reserved2:11; /* zero */ + } fields; + } gpcr_s; /* Generic PIO control set */ + union ioc4_gpcr gpcr_c; /* Generic PIO control clear */ + union ioc4_gpdr { + uint32_t raw; + struct { + uint32_t gen_pin:8; /* State of pins */ + uint32_t reserved:24; + } fields; + } gpdr; /* Generic PIO data */ + uint32_t unused3; + union ioc4_gppr { + uint32_t raw; + struct { + uint32_t gen_pin:1; /* Single pin state */ + uint32_t reserved:31; + } fields; + } gppr[8]; /* Generic PIO pins */ +}; + +/* One of these per IOC4 + * + * The idd_serial_data field is present here, even though it's used + * solely by the serial subdriver, because the main IOC4 module + * properly owns pci_{get,set}_drvdata functionality. This field + * allows that subdriver to stash its own drvdata somewhere. + */ +struct ioc4_driver_data { + struct list_head idd_list; + unsigned long idd_bar0; + struct pci_dev *idd_pdev; + const struct pci_device_id *idd_pci_id; + struct __iomem ioc4_misc_regs *idd_misc_regs; + void *idd_serial_data; +}; + +/* One per submodule */ +struct ioc4_submodule { + struct list_head is_list; + char *is_name; + struct module *is_owner; + int (*is_probe) (struct ioc4_driver_data *); + int (*is_remove) (struct ioc4_driver_data *); +}; + +#define IOC4_NUM_CARDS 8 /* max cards per partition */ + +/********************************** + * Functions needed by submodules * + **********************************/ + +extern int ioc4_register_submodule(struct ioc4_submodule *); +extern void ioc4_unregister_submodule(struct ioc4_submodule *); + +#endif /* _LINUX_IOC4_H */ diff --git a/include/linux/ioc4_common.h b/include/linux/ioc4_common.h deleted file mode 100644 index b03bcc4..0000000 --- a/include/linux/ioc4_common.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. - */ - -#ifndef _LINUX_IOC4_COMMON_H -#define _LINUX_IOC4_COMMON_H - -/* prototypes */ - -int ioc4_serial_init(void); - -int ioc4_serial_attach_one(struct pci_dev *pdev, const struct - pci_device_id *pci_id); -int ioc4_ide_attach_one(struct pci_dev *pdev, const struct - pci_device_id *pci_id); - -#endif /* _LINUX_IOC4_COMMON_H */ -- cgit v0.10.2 From e5d310b349b2cbcc0dab31139c92201f332695bb Mon Sep 17 00:00:00 2001 From: Brent Casavant Date: Tue, 21 Jun 2005 17:16:01 -0700 Subject: [PATCH] ioc4: CONFIG split The SGI IOC4 I/O controller chip drivers are currently all configured by CONFIG_BLK_DEV_SGIIOC4. This is undesirable as not all IOC4 hardware features are needed by all systems. This patch adds two configuration variables, CONFIG_SGI_IOC4 for core IOC4 driver support (see patch 1/3 in this series for further explanation) and CONFIG_SERIAL_SGI_IOC4 to independently enable serial port support. Signed-off-by: Brent Casavant Acked-by: Pat Gefre Acked-by: Jeremy Higdon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig index 6ff7107..a01bb02 100644 --- a/arch/ia64/configs/sn2_defconfig +++ b/arch/ia64/configs/sn2_defconfig @@ -588,6 +588,7 @@ CONFIG_SGI_MBCS=m CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_SGI_L1_CONSOLE=y +CONFIG_SERIAL_SGI_IOC4=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -788,6 +789,11 @@ CONFIG_INFINIBAND_IPOIB=m # CONFIG_INFINIBAND_IPOIB_DEBUG is not set # +# SN Devices +# +CONFIG_SGI_IOC4=y + +# # File systems # CONFIG_EXT2_FS=y diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig index 7539e83..9997ef4 100644 --- a/arch/ia64/defconfig +++ b/arch/ia64/defconfig @@ -638,6 +638,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_SGI_L1_CONSOLE=y +CONFIG_SERIAL_SGI_IOC4=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -943,6 +944,11 @@ CONFIG_INFINIBAND_IPOIB=m # CONFIG_INFINIBAND_IPOIB_DEBUG is not set # +# SN Devices +# +CONFIG_SGI_IOC4=y + +# # File systems # CONFIG_EXT2_FS=y diff --git a/drivers/Kconfig b/drivers/Kconfig index ed41d90..aed4a9b 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -58,4 +58,6 @@ source "drivers/mmc/Kconfig" source "drivers/infiniband/Kconfig" +source "drivers/sn/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 15681de..3167be5 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -61,6 +61,6 @@ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_INFINIBAND) += infiniband/ -obj-$(CONFIG_BLK_DEV_SGIIOC4) += sn/ +obj-$(CONFIG_SGI_IOC4) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 3ac0a53..0273f12 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -672,8 +672,8 @@ config BLK_DEV_SVWKS chipsets. config BLK_DEV_SGIIOC4 - tristate "Silicon Graphics IOC4 chipset support" - depends on IA64_SGI_SN2 || IA64_GENERIC + tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support" + depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4 help This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4 chipset, which has one channel and can support two devices. diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 6a15703..25fcef2 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -843,4 +843,13 @@ config SERIAL_JSM To compile this driver as a module, choose M here: the module will be called jsm. +config SERIAL_SGI_IOC4 + tristate "SGI IOC4 controller serial support" + depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4 + select SERIAL_CORE + help + If you have an SGI Altix with an IOC4 based Base IO card + and wish to use the serial ports on this card, say Y. + Otherwise, say N. + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 81b77d76..8f1cdde 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -51,4 +51,4 @@ obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o -obj-$(CONFIG_BLK_DEV_SGIIOC4) += ioc4_serial.o +obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig new file mode 100644 index 0000000..20f7515 --- /dev/null +++ b/drivers/sn/Kconfig @@ -0,0 +1,20 @@ +# +# Miscellaneous SN-specific devices +# + +menu "SN Devices" + +config SGI_IOC4 + tristate "SGI IOC4 Base IO support" + depends on IA64_GENERIC || IA64_SGI_SN2 + default m + ---help--- + This option enables basic support for the SGI IOC4-based Base IO + controller card. This option does not enable any specific + functions on such a card, but provides necessary infrastructure + for other drivers to utilize. + + If you have an SGI Altix with an IOC4-based + I/O controller say Y. Otherwise say N. + +endmenu diff --git a/drivers/sn/Makefile b/drivers/sn/Makefile index 631e549..c2a2841 100644 --- a/drivers/sn/Makefile +++ b/drivers/sn/Makefile @@ -3,4 +3,4 @@ # # -obj-$(CONFIG_BLK_DEV_SGIIOC4) += ioc4.o +obj-$(CONFIG_SGI_IOC4) += ioc4.o -- cgit v0.10.2 From d4c477ca5448f19afaaf6c0cfd655009ea9e614d Mon Sep 17 00:00:00 2001 From: Brent Casavant Date: Tue, 21 Jun 2005 17:16:01 -0700 Subject: [PATCH] ioc4: PCI bus speed detection Several hardware features of SGI's IOC4 I/O controller chip require timing-related driver calculations dependent upon the PCI bus speed. This patch enables the core IOC4 driver code to detect the actual bus speed and store a value that can later be used by the IOC4 subdrivers as needed. Signed-off-by: Brent Casavant Acked-by: Pat Gefre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index da5f10e..793c3a7 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -299,7 +299,6 @@ struct ioc4_serial { } ioc4_serial; /* UART clock speed */ -#define IOC4_SER_XIN_CLK IOC4_SER_XIN_CLK_66 #define IOC4_SER_XIN_CLK_66 66666667 #define IOC4_SER_XIN_CLK_33 33333333 @@ -1012,21 +1011,20 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) * ioc4_attach_local - Device initialization. * Called at *_attach() time for each * IOC4 with serial ports in the system. - * @control: ioc4_control ptr - * @pdev: PCI handle for this device - * @soft: soft struct for this device - * @ioc4: ioc4 mem space + * @idd: Master module data for this IOC4 */ -static int inline ioc4_attach_local(struct pci_dev *pdev, - struct ioc4_control *control, - struct ioc4_soft *soft, void __iomem *ioc4_misc, - void __iomem *ioc4_serial) +static int inline ioc4_attach_local(struct ioc4_driver_data *idd) { struct ioc4_port *port; struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS]; int port_number; uint16_t ioc4_revid_min = 62; uint16_t ioc4_revid; + struct pci_dev *pdev = idd->idd_pdev; + struct ioc4_control* control = idd->idd_serial_data; + struct ioc4_soft *soft = control->ic_soft; + void __iomem *ioc4_misc = idd->idd_misc_regs; + void __iomem *ioc4_serial = soft->is_ioc4_serial_addr; /* IOC4 firmware must be at least rev 62 */ pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid); @@ -1063,7 +1061,15 @@ static int inline ioc4_attach_local(struct pci_dev *pdev, port->ip_ioc4_soft = soft; port->ip_pdev = pdev; port->ip_ienb = 0; - port->ip_pci_bus_speed = IOC4_SER_XIN_CLK; + /* Use baud rate calculations based on detected PCI + * bus speed. Simply test whether the PCI clock is + * running closer to 66MHz or 33MHz. + */ + if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) { + port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66; + } else { + port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33; + } port->ip_baud = 9600; port->ip_control = control; port->ip_mem = ioc4_misc; @@ -2733,9 +2739,8 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) "%s : request_irq fails for IRQ 0x%x\n ", __FUNCTION__, idd->idd_pdev->irq); } - if ((ret = ioc4_attach_local(idd->idd_pdev, control, soft, - soft->is_ioc4_misc_addr, - soft->is_ioc4_serial_addr))) + ret = ioc4_attach_local(idd); + if (ret) goto out4; /* register port with the serial core */ diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig index 20f7515..13b8d24 100644 --- a/drivers/sn/Kconfig +++ b/drivers/sn/Kconfig @@ -6,7 +6,7 @@ menu "SN Devices" config SGI_IOC4 tristate "SGI IOC4 Base IO support" - depends on IA64_GENERIC || IA64_SGI_SN2 + depends on (IA64_GENERIC || IA64_SGI_SN2) && MMTIMER default m ---help--- This option enables basic support for the SGI IOC4-based Base IO diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c index 70862d7..ea75b3d 100644 --- a/drivers/sn/ioc4.c +++ b/drivers/sn/ioc4.c @@ -29,7 +29,26 @@ #include #include #include +#include +#include #include +#include +#include +#include + +/*************** + * Definitions * + ***************/ + +/* Tweakable values */ + +/* PCI bus speed detection/calibration */ +#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */ +#define IOC4_CALIBRATE_CYCLES 256 /* Average over this many cycles */ +#define IOC4_CALIBRATE_DISCARD 2 /* Discard first few cycles */ +#define IOC4_CALIBRATE_LOW_MHZ 25 /* Lower bound on bus speed sanity */ +#define IOC4_CALIBRATE_HIGH_MHZ 75 /* Upper bound on bus speed sanity */ +#define IOC4_CALIBRATE_DEFAULT_MHZ 66 /* Assumed if sanity check fails */ /************************ * Submodule management * @@ -101,6 +120,112 @@ ioc4_unregister_submodule(struct ioc4_submodule *is) * Device management * *********************/ +#define IOC4_CALIBRATE_LOW_LIMIT \ + (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_LOW_MHZ) +#define IOC4_CALIBRATE_HIGH_LIMIT \ + (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_HIGH_MHZ) +#define IOC4_CALIBRATE_DEFAULT \ + (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_DEFAULT_MHZ) + +#define IOC4_CALIBRATE_END \ + (IOC4_CALIBRATE_CYCLES + IOC4_CALIBRATE_DISCARD) + +#define IOC4_INT_OUT_MODE_TOGGLE 0x7 /* Toggle INT_OUT every COUNT+1 ticks */ + +/* Determines external interrupt output clock period of the PCI bus an + * IOC4 is attached to. This value can be used to determine the PCI + * bus speed. + * + * IOC4 has a design feature that various internal timers are derived from + * the PCI bus clock. This causes IOC4 device drivers to need to take the + * bus speed into account when setting various register values (e.g. INT_OUT + * register COUNT field, UART divisors, etc). Since this information is + * needed by several subdrivers, it is determined by the main IOC4 driver, + * even though the following code utilizes external interrupt registers + * to perform the speed calculation. + */ +static void +ioc4_clock_calibrate(struct ioc4_driver_data *idd) +{ + extern unsigned long sn_rtc_cycles_per_second; + union ioc4_int_out int_out; + union ioc4_gpcr gpcr; + unsigned int state, last_state = 1; + uint64_t start = 0, end, period; + unsigned int count = 0; + + /* Enable output */ + gpcr.raw = 0; + gpcr.fields.dir = IOC4_GPCR_DIR_0; + gpcr.fields.int_out_en = 1; + writel(gpcr.raw, &idd->idd_misc_regs->gpcr_s.raw); + + /* Reset to power-on state */ + writel(0, &idd->idd_misc_regs->int_out.raw); + mmiowb(); + + printk(KERN_INFO + "%s: Calibrating PCI bus speed " + "for pci_dev %s ... ", __FUNCTION__, pci_name(idd->idd_pdev)); + /* Set up square wave */ + int_out.raw = 0; + int_out.fields.count = IOC4_CALIBRATE_COUNT; + int_out.fields.mode = IOC4_INT_OUT_MODE_TOGGLE; + int_out.fields.diag = 0; + writel(int_out.raw, &idd->idd_misc_regs->int_out.raw); + mmiowb(); + + /* Check square wave period averaged over some number of cycles */ + do { + int_out.raw = readl(&idd->idd_misc_regs->int_out.raw); + state = int_out.fields.int_out; + if (!last_state && state) { + count++; + if (count == IOC4_CALIBRATE_END) { + end = rtc_time(); + break; + } else if (count == IOC4_CALIBRATE_DISCARD) + start = rtc_time(); + } + last_state = state; + } while (1); + + /* Calculation rearranged to preserve intermediate precision. + * Logically: + * 1. "end - start" gives us number of RTC cycles over all the + * square wave cycles measured. + * 2. Divide by number of square wave cycles to get number of + * RTC cycles per square wave cycle. + * 3. Divide by 2*(int_out.fields.count+1), which is the formula + * by which the IOC4 generates the square wave, to get the + * number of RTC cycles per IOC4 INT_OUT count. + * 4. Divide by sn_rtc_cycles_per_second to get seconds per + * count. + * 5. Multiply by 1E9 to get nanoseconds per count. + */ + period = ((end - start) * 1000000000) / + (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1) + * sn_rtc_cycles_per_second); + + /* Bounds check the result. */ + if (period > IOC4_CALIBRATE_LOW_LIMIT || + period < IOC4_CALIBRATE_HIGH_LIMIT) { + printk("failed. Assuming PCI clock ticks are %d ns.\n", + IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR); + period = IOC4_CALIBRATE_DEFAULT; + } else { + printk("succeeded. PCI clock ticks are %ld ns.\n", + period / IOC4_EXTINT_COUNT_DIVISOR); + } + + /* Remember results. We store the extint clock period rather + * than the PCI clock period so that greater precision is + * retained. Divide by IOC4_EXTINT_COUNT_DIVISOR to get + * PCI clock period. + */ + idd->count_period = period; +} + /* Adds a new instance of an IOC4 card */ static int ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) @@ -170,6 +295,9 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) pci_write_config_dword(idd->idd_pdev, PCI_COMMAND, pcmd | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); + /* Determine PCI clock */ + ioc4_clock_calibrate(idd); + /* Disable/clear all interrupts. Need to do this here lest * one submodule request the shared IOC4 IRQ, but interrupt * is generated by a different subdevice. diff --git a/include/linux/ioc4.h b/include/linux/ioc4.h index 729bfa4..3dd18b7 100644 --- a/include/linux/ioc4.h +++ b/include/linux/ioc4.h @@ -11,6 +11,14 @@ #include +/*************** + * Definitions * + ***************/ + +/* Miscellaneous values inherent to hardware */ + +#define IOC4_EXTINT_COUNT_DIVISOR 520 /* PCI clocks per COUNT tick */ + /*********************************** * Structures needed by subdrivers * ***********************************/ @@ -119,19 +127,34 @@ struct ioc4_misc_regs { } gppr[8]; /* Generic PIO pins */ }; -/* One of these per IOC4 - * - * The idd_serial_data field is present here, even though it's used - * solely by the serial subdriver, because the main IOC4 module - * properly owns pci_{get,set}_drvdata functionality. This field - * allows that subdriver to stash its own drvdata somewhere. - */ +/* Masks for GPCR DIR pins */ +#define IOC4_GPCR_DIR_0 0x01 /* External interrupt output */ +#define IOC4_GPCR_DIR_1 0x02 /* External interrupt input */ +#define IOC4_GPCR_DIR_2 0x04 +#define IOC4_GPCR_DIR_3 0x08 /* Keyboard/mouse presence */ +#define IOC4_GPCR_DIR_4 0x10 /* Ser. port 0 xcvr select (0=232, 1=422) */ +#define IOC4_GPCR_DIR_5 0x20 /* Ser. port 1 xcvr select (0=232, 1=422) */ +#define IOC4_GPCR_DIR_6 0x40 /* Ser. port 2 xcvr select (0=232, 1=422) */ +#define IOC4_GPCR_DIR_7 0x80 /* Ser. port 3 xcvr select (0=232, 1=422) */ + +/* Masks for GPCR EDGE pins */ +#define IOC4_GPCR_EDGE_0 0x01 +#define IOC4_GPCR_EDGE_1 0x02 /* External interrupt input */ +#define IOC4_GPCR_EDGE_2 0x04 +#define IOC4_GPCR_EDGE_3 0x08 +#define IOC4_GPCR_EDGE_4 0x10 +#define IOC4_GPCR_EDGE_5 0x20 +#define IOC4_GPCR_EDGE_6 0x40 +#define IOC4_GPCR_EDGE_7 0x80 + +/* One of these per IOC4 */ struct ioc4_driver_data { struct list_head idd_list; unsigned long idd_bar0; struct pci_dev *idd_pdev; const struct pci_device_id *idd_pci_id; struct __iomem ioc4_misc_regs *idd_misc_regs; + unsigned long count_period; void *idd_serial_data; }; -- cgit v0.10.2 From 2368086344c3d67b0f4aecac39d620fb9b8795c3 Mon Sep 17 00:00:00 2001 From: Hirokazu Takata Date: Tue, 21 Jun 2005 17:16:10 -0700 Subject: [PATCH] m32r: Support M3A-2170(Mappi-III) platform This patchset is for supporting a new m32r platform, M3A-2170(Mappi-III) evaluation board. An M32R chip multiprocessor is equipped on the board. http://http://www.linux-m32r.org/eng/platform/platform.html * arch/m32r/Kconfig: Support Mappi-III platform. * arch/m32r/kernel/Makefile: ditto. * arch/m32r/kernel/io_mappi3.c: ditto. * arch/m32r/kernel/setup.c: ditto. * arch/m32r/kernel/setup_mappi3.c: ditto. * include/asm-m32r/m32102.h: ditto. * include/asm-m32r/m32r.h: ditto. * include/asm-m32r/mappi3/mappi3_pld.h: ditto. * include/asm-m32r/ide.h: CF support for Mappi-III. * arch/m32r/kernel/setup_mappi3.c: ditto. * arch/m32r/mappi3/defconfig.smp: A default config file for Mappi-III. * arch/m32r/mappi3/dot.gdbinit: A default .gdbinit file for Mappi-III. * arch/m32r/boot/compressed/m32r_sio.c: Modified for Mappi-III - At boot time, m32r-g00ff bootloader makes MMU off for Mappi-III, on the contrary it makes MMU on for Mappi-II. * arch/m32r/kernel/io_mappi2.c: Update comments. * arch/m32r/kernel/setup_mappi2.c: ditto. Signed-off-by: Mamoru Sakugawa Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 0d90ea5..64c13334 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -78,6 +78,9 @@ config PLAT_OAKS32R config PLAT_MAPPI2 bool "Mappi-II(M3A-ZA36/M3A-ZA52)" +config PLAT_MAPPI3 + bool "Mappi-III(M3A-2170)" + endchoice choice @@ -134,6 +137,7 @@ config BUS_CLOCK int "Bus Clock [Hz] (integer)" default "70000000" if PLAT_MAPPI default "25000000" if PLAT_USRV + default "50000000" if PLAT_MAPPI3 default "50000000" if PLAT_M32700UT default "50000000" if PLAT_OPSPUT default "33333333" if PLAT_OAKS32R @@ -149,7 +153,7 @@ config CPU_LITTLE_ENDIAN config MEMORY_START hex "Physical memory start address (hex)" - default "08000000" if PLAT_MAPPI || PLAT_MAPPI2 + default "08000000" if PLAT_MAPPI || PLAT_MAPPI2 || PLAT_MAPPI3 default "08000000" if PLAT_USRV default "08000000" if PLAT_M32700UT default "08000000" if PLAT_OPSPUT @@ -157,6 +161,7 @@ config MEMORY_START config MEMORY_SIZE hex "Physical memory size (hex)" + default "08000000" if PLAT_MAPPI3 default "04000000" if PLAT_MAPPI || PLAT_MAPPI2 default "02000000" if PLAT_USRV default "01000000" if PLAT_M32700UT diff --git a/arch/m32r/boot/compressed/m32r_sio.c b/arch/m32r/boot/compressed/m32r_sio.c index bad5475..8f9a572 100644 --- a/arch/m32r/boot/compressed/m32r_sio.c +++ b/arch/m32r/boot/compressed/m32r_sio.c @@ -6,6 +6,7 @@ */ #include +#include static void putc(char c); @@ -38,16 +39,17 @@ static int puts(const char *s) static void putc(char c) { - - while ((*BOOT_SIO0STS & 0x3) != 0x3) ; + while ((*BOOT_SIO0STS & 0x3) != 0x3) + cpu_relax(); if (c == '\n') { *BOOT_SIO0TXB = '\r'; - while ((*BOOT_SIO0STS & 0x3) != 0x3) ; + while ((*BOOT_SIO0STS & 0x3) != 0x3) + cpu_relax(); } *BOOT_SIO0TXB = c; } -#else /* defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) */ -#ifdef CONFIG_MMU +#else /* !(CONFIG_PLAT_M32700UT_Alpha) && !(CONFIG_PLAT_M32700UT) */ +#if defined(CONFIG_PLAT_MAPPI2) #define SIO0STS (volatile unsigned short *)(0xa0efd000 + 14) #define SIO0TXB (volatile unsigned short *)(0xa0efd000 + 30) #else @@ -57,11 +59,12 @@ static void putc(char c) static void putc(char c) { - - while ((*SIO0STS & 0x1) == 0) ; + while ((*SIO0STS & 0x1) == 0) + cpu_relax(); if (c == '\n') { *SIO0TXB = '\r'; - while ((*SIO0STS & 0x1) == 0) ; + while ((*SIO0STS & 0x1) == 0) + cpu_relax(); } *SIO0TXB = c; } diff --git a/arch/m32r/kernel/Makefile b/arch/m32r/kernel/Makefile index cfd690b..6c6b6c3 100644 --- a/arch/m32r/kernel/Makefile +++ b/arch/m32r/kernel/Makefile @@ -10,6 +10,7 @@ obj-y := process.o entry.o traps.o align.o irq.o setup.o time.o \ obj-$(CONFIG_SMP) += smp.o smpboot.o obj-$(CONFIG_PLAT_MAPPI) += setup_mappi.o io_mappi.o obj-$(CONFIG_PLAT_MAPPI2) += setup_mappi2.o io_mappi2.o +obj-$(CONFIG_PLAT_MAPPI3) += setup_mappi3.o io_mappi3.o obj-$(CONFIG_PLAT_USRV) += setup_usrv.o io_usrv.o obj-$(CONFIG_PLAT_M32700UT) += setup_m32700ut.o io_m32700ut.o obj-$(CONFIG_PLAT_OPSPUT) += setup_opsput.o io_opsput.o @@ -17,4 +18,3 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_PLAT_OAKS32R) += setup_oaks32r.o io_oaks32r.o EXTRA_AFLAGS := -traditional - diff --git a/arch/m32r/kernel/io_m32700ut.c b/arch/m32r/kernel/io_m32700ut.c index 371ba904..e545b06 100644 --- a/arch/m32r/kernel/io_m32700ut.c +++ b/arch/m32r/kernel/io_m32700ut.c @@ -3,8 +3,8 @@ * * Typical I/O routines for M32700UT board. * - * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, - * Hitoshi Yamamoto, Takeo Takahashi + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi * * This file is subject to the terms and conditions of the GNU General * Public License. See the file "COPYING" in the main directory of this @@ -172,64 +172,21 @@ unsigned long _inl(unsigned long port) unsigned char _inb_p(unsigned long port) { - unsigned char v; - - if (port >= LAN_IOSTART && port < LAN_IOEND) - v = _ne_inb(PORT2ADDR_NE(port)); - else -#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) - if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { - return *(volatile unsigned char *)__port2addr_ata(port); - } else -#endif -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - unsigned char b; - pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); - return b; - } else -#endif - v = *(volatile unsigned char *)PORT2ADDR(port); - + unsigned char v = _inb(port); delay(); return (v); } unsigned short _inw_p(unsigned long port) { - unsigned short v; - - if (port >= LAN_IOSTART && port < LAN_IOEND) - v = _ne_inw(PORT2ADDR_NE(port)); - else -#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) - if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { - return *(volatile unsigned short *)__port2addr_ata(port); - } else -#endif -#if defined(CONFIG_USB) - if(port >= 0x340 && port < 0x3a0) - return *(volatile unsigned short *)PORT2ADDR_USB(port); - else -#endif -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - unsigned short w; - pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); - return w; - } else -#endif - v = *(volatile unsigned short *)PORT2ADDR(port); - + unsigned short v = _inw(port); delay(); return (v); } unsigned long _inl_p(unsigned long port) { - unsigned long v; - - v = *(volatile unsigned long *)PORT2ADDR(port); + unsigned long v = _inl(port); delay(); return (v); } @@ -287,52 +244,19 @@ void _outl(unsigned long l, unsigned long port) void _outb_p(unsigned char b, unsigned long port) { - if (port >= LAN_IOSTART && port < LAN_IOEND) - _ne_outb(b, PORT2ADDR_NE(port)); - else -#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) - if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { - *(volatile unsigned char *)__port2addr_ata(port) = b; - } else -#endif -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); - } else -#endif - *(volatile unsigned char *)PORT2ADDR(port) = b; - + _outb(b, port); delay(); } void _outw_p(unsigned short w, unsigned long port) { - if (port >= LAN_IOSTART && port < LAN_IOEND) - _ne_outw(w, PORT2ADDR_NE(port)); - else -#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) - if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { - *(volatile unsigned short *)__port2addr_ata(port) = w; - } else -#endif -#if defined(CONFIG_USB) - if(port >= 0x340 && port < 0x3a0) - *(volatile unsigned short *)PORT2ADDR_USB(port) = w; - else -#endif -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); - } else -#endif - *(volatile unsigned short *)PORT2ADDR(port) = w; - + _outw(w, port); delay(); } void _outl_p(unsigned long l, unsigned long port) { - *(volatile unsigned long *)PORT2ADDR(port) = l; + _outl(l, port); delay(); } diff --git a/arch/m32r/kernel/io_mappi.c b/arch/m32r/kernel/io_mappi.c index 85688ff..7803316 100644 --- a/arch/m32r/kernel/io_mappi.c +++ b/arch/m32r/kernel/io_mappi.c @@ -3,8 +3,8 @@ * * Typical I/O routines for Mappi board. * - * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, - * Hitoshi Yamamoto + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto */ #include @@ -130,57 +130,21 @@ unsigned long _inl(unsigned long port) unsigned char _inb_p(unsigned long port) { - unsigned char v; - - if (port >= 0x300 && port < 0x320) - v = _ne_inb(PORT2ADDR_NE(port)); - else -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - unsigned char b; - pcc_ioread(0, port, &b, sizeof(b), 1, 0); - return b; - } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { - unsigned char b; - pcc_ioread(1, port, &b, sizeof(b), 1, 0); - return b; - } else -#endif - v = *(volatile unsigned char *)PORT2ADDR(port); - + unsigned char v = _inb(port); delay(); return (v); } unsigned short _inw_p(unsigned long port) { - unsigned short v; - - if (port >= 0x300 && port < 0x320) - v = _ne_inw(PORT2ADDR_NE(port)); - else -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - unsigned short w; - pcc_ioread(0, port, &w, sizeof(w), 1, 0); - return w; - } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { - unsigned short w; - pcc_ioread(1, port, &w, sizeof(w), 1, 0); - return w; - } else -#endif - v = *(volatile unsigned short *)PORT2ADDR(port); - + unsigned short v = _inw(port); delay(); return (v); } unsigned long _inl_p(unsigned long port) { - unsigned long v; - - v = *(volatile unsigned long *)PORT2ADDR(port); + unsigned long v = _inl(port); delay(); return (v); } @@ -229,41 +193,19 @@ void _outl(unsigned long l, unsigned long port) void _outb_p(unsigned char b, unsigned long port) { - if (port >= 0x300 && port < 0x320) - _ne_outb(b, PORT2ADDR_NE(port)); - else -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - pcc_iowrite(0, port, &b, sizeof(b), 1, 0); - } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { - pcc_iowrite(1, port, &b, sizeof(b), 1, 0); - } else -#endif - *(volatile unsigned char *)PORT2ADDR(port) = b; - + _outb(b, port); delay(); } void _outw_p(unsigned short w, unsigned long port) { - if (port >= 0x300 && port < 0x320) - _ne_outw(w, PORT2ADDR_NE(port)); - else -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - pcc_iowrite(0, port, &w, sizeof(w), 1, 0); - } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { - pcc_iowrite(1, port, &w, sizeof(w), 1, 0); - } else -#endif - *(volatile unsigned short *)PORT2ADDR(port) = w; - + _outw(w, port); delay(); } void _outl_p(unsigned long l, unsigned long port) { - *(volatile unsigned long *)PORT2ADDR(port) = l; + _outl(l, port); delay(); } diff --git a/arch/m32r/kernel/io_mappi2.c b/arch/m32r/kernel/io_mappi2.c index 4182cd4..5c03504 100644 --- a/arch/m32r/kernel/io_mappi2.c +++ b/arch/m32r/kernel/io_mappi2.c @@ -3,7 +3,7 @@ * * Typical I/O routines for Mappi2 board. * - * Copyright (c) 2001-2003 Hiroyuki Kondo, Hirokazu Takata, + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, * Hitoshi Yamamoto, Mamoru Sakugawa */ @@ -25,7 +25,7 @@ extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); -#endif /* CONFIG_PCMCIA && CONFIG_MAPPI2_CFC */ +#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */ #define PORT2ADDR(port) _port2addr(port) #define PORT2ADDR_NE(port) _port2addr_ne(port) @@ -169,64 +169,21 @@ unsigned long _inl(unsigned long port) unsigned char _inb_p(unsigned long port) { - unsigned char v; - - if (port >= LAN_IOSTART && port < LAN_IOEND) - v = _ne_inb(PORT2ADDR_NE(port)); - else -#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) - if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { - return *(volatile unsigned char *)__port2addr_ata(port); - } else -#endif -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - unsigned char b; - pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); - return b; - } else -#endif - v = *(volatile unsigned char *)PORT2ADDR(port); - + unsigned char v = _inb(port); delay(); return (v); } unsigned short _inw_p(unsigned long port) { - unsigned short v; - - if (port >= LAN_IOSTART && port < LAN_IOEND) - v = _ne_inw(PORT2ADDR_NE(port)); - else -#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) - if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { - return *(volatile unsigned short *)__port2addr_ata(port); - } else -#endif -#if defined(CONFIG_USB) - if (port >= 0x340 && port < 0x3a0) - v = *(volatile unsigned short *)PORT2ADDR_USB(port); - else -#endif -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - unsigned short w; - pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); - return w; - } else -#endif - v = *(volatile unsigned short *)PORT2ADDR(port); - + unsigned short v = _inw(port); delay(); return (v); } unsigned long _inl_p(unsigned long port) { - unsigned long v; - - v = *(volatile unsigned long *)PORT2ADDR(port); + unsigned long v = _inl(port); delay(); return (v); } @@ -284,52 +241,19 @@ void _outl(unsigned long l, unsigned long port) void _outb_p(unsigned char b, unsigned long port) { - if (port >= LAN_IOSTART && port < LAN_IOEND) - _ne_outb(b, PORT2ADDR_NE(port)); - else -#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) - if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { - *(volatile unsigned char *)__port2addr_ata(port) = b; - } else -#endif -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); - } else -#endif - *(volatile unsigned char *)PORT2ADDR(port) = b; - + _outb(b, port); delay(); } void _outw_p(unsigned short w, unsigned long port) { - if (port >= LAN_IOSTART && port < LAN_IOEND) - _ne_outw(w, PORT2ADDR_NE(port)); - else -#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) - if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { - *(volatile unsigned short *)__port2addr_ata(port) = w; - } else -#endif -#if defined(CONFIG_USB) - if (port >= 0x340 && port < 0x3a0) - *(volatile unsigned short *)PORT2ADDR_USB(port) = w; - else -#endif -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); - } else -#endif - *(volatile unsigned short *)PORT2ADDR(port) = w; - + _outw(w, port); delay(); } void _outl_p(unsigned long l, unsigned long port) { - *(volatile unsigned long *)PORT2ADDR(port) = l; + _outl(l, port); delay(); } diff --git a/arch/m32r/kernel/io_mappi3.c b/arch/m32r/kernel/io_mappi3.c new file mode 100644 index 0000000..c80bde6 --- /dev/null +++ b/arch/m32r/kernel/io_mappi3.c @@ -0,0 +1,378 @@ +/* + * linux/arch/m32r/kernel/io_mappi3.c + * + * Typical I/O routines for Mappi3 board. + * + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa + */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) +#include + +#define M32R_PCC_IOMAP_SIZE 0x1000 + +#define M32R_PCC_IOSTART0 0x1000 +#define M32R_PCC_IOEND0 (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1) + +extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int); +extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); +#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */ + +#define PORT2ADDR(port) _port2addr(port) +#define PORT2ADDR_NE(port) _port2addr_ne(port) +#define PORT2ADDR_USB(port) _port2addr_usb(port) + +static inline void *_port2addr(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET); +} + +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 + +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) +static inline void *__port2addr_ata(unsigned long port) +{ + static int dummy_reg; + + switch (port) { + case 0x1f0: return (void *)0xb4002000; + case 0x1f1: return (void *)0xb4012800; + case 0x1f2: return (void *)0xb4012002; + case 0x1f3: return (void *)0xb4012802; + case 0x1f4: return (void *)0xb4012004; + case 0x1f5: return (void *)0xb4012804; + case 0x1f6: return (void *)0xb4012006; + case 0x1f7: return (void *)0xb4012806; + case 0x3f6: return (void *)0xb401200e; + default: return (void *)&dummy_reg; + } +} +#endif + +static inline void *_port2addr_ne(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x10000000); +} + +static inline void *_port2addr_usb(unsigned long port) +{ + return (void *)(port + NONCACHE_OFFSET + 0x12000000); +} +static inline void delay(void) +{ + __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); +} + +/* + * NIC I/O function + */ + +static inline unsigned char _ne_inb(void *portp) +{ + return (unsigned char) *(volatile unsigned char *)portp; +} + +static inline unsigned short _ne_inw(void *portp) +{ + return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp); +} + +static inline void _ne_insb(void *portp, void * addr, unsigned long count) +{ + unsigned char *buf = addr; + + while (count--) + *buf++ = *(volatile unsigned char *)portp; +} + +static inline void _ne_outb(unsigned char b, void *portp) +{ + *(volatile unsigned char *)portp = (unsigned char)b; +} + +static inline void _ne_outw(unsigned short w, void *portp) +{ + *(volatile unsigned short *)portp = cpu_to_le16(w); +} + +unsigned char _inb(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inb(PORT2ADDR_NE(port)); +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + return *(volatile unsigned char *)__port2addr_ata(port); + } +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned char b; + pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); + return b; + } else +#endif + return *(volatile unsigned char *)PORT2ADDR(port); +} + +unsigned short _inw(unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + return _ne_inw(PORT2ADDR_NE(port)); +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + return *(volatile unsigned short *)__port2addr_ata(port); + } +#endif +#if defined(CONFIG_USB) + else if (port >= 0x340 && port < 0x3a0) + return *(volatile unsigned short *)PORT2ADDR_USB(port); +#endif + +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned short w; + pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); + return w; + } else +#endif + return *(volatile unsigned short *)PORT2ADDR(port); +} + +unsigned long _inl(unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + unsigned long l; + pcc_ioread_word(0, port, &l, sizeof(l), 1, 0); + return l; + } else +#endif + return *(volatile unsigned long *)PORT2ADDR(port); +} + +unsigned char _inb_p(unsigned long port) +{ + unsigned char v = _inb(port); + delay(); + return (v); +} + +unsigned short _inw_p(unsigned long port) +{ + unsigned short v = _inw(port); + delay(); + return (v); +} + +unsigned long _inl_p(unsigned long port) +{ + unsigned long v = _inl(port); + delay(); + return (v); +} + +void _outb(unsigned char b, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outb(b, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + *(volatile unsigned char *)__port2addr_ata(port) = b; + } else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); + } else +#endif + *(volatile unsigned char *)PORT2ADDR(port) = b; +} + +void _outw(unsigned short w, unsigned long port) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_outw(w, PORT2ADDR_NE(port)); + else +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + *(volatile unsigned short *)__port2addr_ata(port) = w; + } else +#endif +#if defined(CONFIG_USB) + if (port >= 0x340 && port < 0x3a0) + *(volatile unsigned short *)PORT2ADDR_USB(port) = w; + else +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); + } else +#endif + *(volatile unsigned short *)PORT2ADDR(port) = w; +} + +void _outl(unsigned long l, unsigned long port) +{ +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0); + } else +#endif + *(volatile unsigned long *)PORT2ADDR(port) = l; +} + +void _outb_p(unsigned char b, unsigned long port) +{ + _outb(b, port); + delay(); +} + +void _outw_p(unsigned short w, unsigned long port) +{ + _outw(w, port); + delay(); +} + +void _outl_p(unsigned long l, unsigned long port) +{ + _outl(l, port); + delay(); +} + +void _insb(unsigned int port, void * addr, unsigned long count) +{ + if (port >= LAN_IOSTART && port < LAN_IOEND) + _ne_insb(PORT2ADDR_NE(port), addr, count); +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + unsigned char *buf = addr; + unsigned char *portp = __port2addr_ata(port); + while (count--) + *buf++ = *(volatile unsigned char *)portp; + } +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), + count, 1); + } +#endif + else { + unsigned char *buf = addr; + unsigned char *portp = PORT2ADDR(port); + while (count--) + *buf++ = *(volatile unsigned char *)portp; + } +} + +void _insw(unsigned int port, void * addr, unsigned long count) +{ + unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + portp = PORT2ADDR_NE(port); + while (count--) + *buf++ = *(volatile unsigned short *)portp; +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), + count, 1); +#endif +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + portp = __port2addr_ata(port); + while (count--) + *buf++ = *(volatile unsigned short *)portp; +#endif + } else { + portp = PORT2ADDR(port); + while (count--) + *buf++ = *(volatile unsigned short *)portp; + } +} + +void _insl(unsigned int port, void * addr, unsigned long count) +{ + unsigned long *buf = addr; + unsigned long *portp; + + portp = PORT2ADDR(port); + while (count--) + *buf++ = *(volatile unsigned long *)portp; +} + +void _outsb(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned char *buf = addr; + unsigned char *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + portp = PORT2ADDR_NE(port); + while (count--) + _ne_outb(*buf++, portp); +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + portp = __port2addr_ata(port); + while (count--) + *(volatile unsigned char *)portp = *buf++; +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), + count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while (count--) + *(volatile unsigned char *)portp = *buf++; + } +} + +void _outsw(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned short *buf = addr; + unsigned short *portp; + + if (port >= LAN_IOSTART && port < LAN_IOEND) { + portp = PORT2ADDR_NE(port); + while (count--) + *(volatile unsigned short *)portp = *buf++; +#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC) + } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) { + portp = __port2addr_ata(port); + while (count--) + *(volatile unsigned short *)portp = *buf++; +#endif +#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) + } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { + pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), + count, 1); +#endif + } else { + portp = PORT2ADDR(port); + while (count--) + *(volatile unsigned short *)portp = *buf++; + } +} + +void _outsl(unsigned int port, const void * addr, unsigned long count) +{ + const unsigned long *buf = addr; + unsigned char *portp; + + portp = PORT2ADDR(port); + while (count--) + *(volatile unsigned long *)portp = *buf++; +} diff --git a/arch/m32r/kernel/io_oaks32r.c b/arch/m32r/kernel/io_oaks32r.c index 2869647..9997ddd 100644 --- a/arch/m32r/kernel/io_oaks32r.c +++ b/arch/m32r/kernel/io_oaks32r.c @@ -3,7 +3,7 @@ * * Typical I/O routines for OAKS32R board. * - * Copyright (c) 2001-2004 Hiroyuki Kondo, Hirokazu Takata, + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, * Hitoshi Yamamoto, Mamoru Sakugawa */ @@ -90,35 +90,21 @@ unsigned long _inl(unsigned long port) unsigned char _inb_p(unsigned long port) { - unsigned char v; - - if (port >= 0x300 && port < 0x320) - v = _ne_inb(PORT2ADDR_NE(port)); - else - v = *(volatile unsigned char *)PORT2ADDR(port); - + unsigned char v = _inb(port); delay(); return (v); } unsigned short _inw_p(unsigned long port) { - unsigned short v; - - if (port >= 0x300 && port < 0x320) - v = _ne_inw(PORT2ADDR_NE(port)); - else - v = *(volatile unsigned short *)PORT2ADDR(port); - + unsigned short v = _inw(port); delay(); return (v); } unsigned long _inl_p(unsigned long port) { - unsigned long v; - - v = *(volatile unsigned long *)PORT2ADDR(port); + unsigned long v = _inl(port); delay(); return (v); } @@ -146,27 +132,19 @@ void _outl(unsigned long l, unsigned long port) void _outb_p(unsigned char b, unsigned long port) { - if (port >= 0x300 && port < 0x320) - _ne_outb(b, PORT2ADDR_NE(port)); - else - *(volatile unsigned char *)PORT2ADDR(port) = b; - + _outb(b, port); delay(); } void _outw_p(unsigned short w, unsigned long port) { - if (port >= 0x300 && port < 0x320) - _ne_outw(w, PORT2ADDR_NE(port)); - else - *(volatile unsigned short *)PORT2ADDR(port) = w; - + _outw(w, port); delay(); } void _outl_p(unsigned long l, unsigned long port) { - *(volatile unsigned long *)PORT2ADDR(port) = l; + _outl(l, port); delay(); } diff --git a/arch/m32r/kernel/io_opsput.c b/arch/m32r/kernel/io_opsput.c index aaf42f9..e34951e 100644 --- a/arch/m32r/kernel/io_opsput.c +++ b/arch/m32r/kernel/io_opsput.c @@ -1,10 +1,10 @@ /* - * linux/arch/m32r/kernel/io_mappi.c + * linux/arch/m32r/kernel/io_opsput.c * * Typical I/O routines for OPSPUT board. * - * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, - * Hitoshi Yamamoto, Takeo Takahashi + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi * * This file is subject to the terms and conditions of the GNU General * Public License. See the file "COPYING" in the main directory of this @@ -98,7 +98,6 @@ unsigned char _inb(unsigned long port) { if (port >= LAN_IOSTART && port < LAN_IOEND) return _ne_inb(PORT2ADDR_NE(port)); - #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { unsigned char b; @@ -118,7 +117,6 @@ unsigned short _inw(unsigned long port) else if(port >= 0x340 && port < 0x3a0) return *(volatile unsigned short *)PORT2ADDR_USB(port); #endif - #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { unsigned short w; @@ -143,55 +141,21 @@ unsigned long _inl(unsigned long port) unsigned char _inb_p(unsigned long port) { - unsigned char v; - - if (port >= LAN_IOSTART && port < LAN_IOEND) - v = _ne_inb(PORT2ADDR_NE(port)); - else -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - unsigned char b; - pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); - return b; - } else -#endif - v = *(volatile unsigned char *)PORT2ADDR(port); - + unsigned char v = _inb(port); delay(); return (v); } unsigned short _inw_p(unsigned long port) { - unsigned short v; - - if (port >= LAN_IOSTART && port < LAN_IOEND) - v = _ne_inw(PORT2ADDR_NE(port)); - else -#if defined(CONFIG_USB) - if(port >= 0x340 && port < 0x3a0) - return *(volatile unsigned short *)PORT2ADDR_USB(port); - else -#endif - -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - unsigned short w; - pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); - return w; - } else -#endif - v = *(volatile unsigned short *)PORT2ADDR(port); - + unsigned short v = _inw(port); delay(); return (v); } unsigned long _inl_p(unsigned long port) { - unsigned long v; - - v = *(volatile unsigned long *)PORT2ADDR(port); + unsigned long v = _inl(port); delay(); return (v); } @@ -219,7 +183,6 @@ void _outw(unsigned short w, unsigned long port) *(volatile unsigned short *)PORT2ADDR_USB(port) = w; else #endif - #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); @@ -240,43 +203,19 @@ void _outl(unsigned long l, unsigned long port) void _outb_p(unsigned char b, unsigned long port) { - if (port >= LAN_IOSTART && port < LAN_IOEND) - _ne_outb(b, PORT2ADDR_NE(port)); - else -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); - } else -#endif - *(volatile unsigned char *)PORT2ADDR(port) = b; - + _outb(b, port); delay(); } void _outw_p(unsigned short w, unsigned long port) { - if (port >= LAN_IOSTART && port < LAN_IOEND) - _ne_outw(w, PORT2ADDR_NE(port)); - else -#if defined(CONFIG_USB) - if(port >= 0x340 && port < 0x3a0) - *(volatile unsigned short *)PORT2ADDR_USB(port) = w; - else -#endif - -#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC) - if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { - pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); - } else -#endif - *(volatile unsigned short *)PORT2ADDR(port) = w; - + _outw(w, port); delay(); } void _outl_p(unsigned long l, unsigned long port) { - *(volatile unsigned long *)PORT2ADDR(port) = l; + _outl(l, port); delay(); } diff --git a/arch/m32r/kernel/io_usrv.c b/arch/m32r/kernel/io_usrv.c index 27928a0..9eb161d 100644 --- a/arch/m32r/kernel/io_usrv.c +++ b/arch/m32r/kernel/io_usrv.c @@ -3,8 +3,8 @@ * * Typical I/O routines for uServer board. * - * Copyright (c) 2001 - 2003 Hiroyuki Kondo, Hirokazu Takata, - * Hitoshi Yamamoto, Takeo Takahashi + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi * * This file is subject to the terms and conditions of the GNU General * Public License. See the file "COPYING" in the main directory of this @@ -39,7 +39,7 @@ extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int); #define PORT2ADDR(port) _port2addr(port) -static __inline__ void *_port2addr(unsigned long port) +static inline void *_port2addr(unsigned long port) { #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) if (port >= UART0_IOSTART && port <= UART0_IOEND) @@ -50,7 +50,7 @@ static __inline__ void *_port2addr(unsigned long port) return (void *)(port + NONCACHE_OFFSET); } -static __inline__ void delay(void) +static inline void delay(void) { __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory"); } @@ -87,39 +87,22 @@ unsigned long _inl(unsigned long port) unsigned char _inb_p(unsigned long port) { - unsigned char b; - - if (port >= CFC_IOSTART && port <= CFC_IOEND) { - pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0); - return b; - } else { - b = *(volatile unsigned char *)PORT2ADDR(port); - delay(); - return b; - } + unsigned char v = _inb(port); + delay(); + return v; } unsigned short _inw_p(unsigned long port) { - unsigned short w; - - if (port >= CFC_IOSTART && port <= CFC_IOEND) { - pcc_ioread_word(0, port, &w, sizeof(w), 1, 0); - return w; - } else { - w = *(volatile unsigned short *)PORT2ADDR(port); - delay(); - return w; - } + unsigned short v = _inw(port); + delay(); + return v; } unsigned long _inl_p(unsigned long port) { - unsigned long v; - - v = *(volatile unsigned long *)PORT2ADDR(port); + unsigned long v = _inl(port); delay(); - return v; } @@ -149,25 +132,19 @@ void _outl(unsigned long l, unsigned long port) void _outb_p(unsigned char b, unsigned long port) { - if (port >= CFC_IOSTART && port <= CFC_IOEND) - pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0); - else - *(volatile unsigned char *)PORT2ADDR(port) = b; + _outb(b, port); delay(); } void _outw_p(unsigned short w, unsigned long port) { - if (port >= CFC_IOSTART && port <= CFC_IOEND) - pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0); - else - *(volatile unsigned short *)PORT2ADDR(port) = w; + _outw(w, port); delay(); } void _outl_p(unsigned long l, unsigned long port) { - *(volatile unsigned long *)PORT2ADDR(port) = l; + _outl(l, port); delay(); } diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c index 4826cd6..ec56747 100644 --- a/arch/m32r/kernel/setup.c +++ b/arch/m32r/kernel/setup.c @@ -330,6 +330,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "Machine\t\t: Mappi Evaluation board\n"); #elif CONFIG_PLAT_MAPPI2 seq_printf(m, "Machine\t\t: Mappi-II Evaluation board\n"); +#elif CONFIG_PLAT_MAPPI3 + seq_printf(m, "Machine\t\t: Mappi-III Evaluation board\n"); #elif CONFIG_PLAT_M32700UT seq_printf(m, "Machine\t\t: M32700UT Evaluation board\n"); #elif CONFIG_PLAT_OPSPUT diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c index 1904d46..248fc65 100644 --- a/arch/m32r/kernel/setup_mappi2.c +++ b/arch/m32r/kernel/setup_mappi2.c @@ -1,5 +1,5 @@ /* - * linux/arch/m32r/kernel/setup_mappi.c + * linux/arch/m32r/kernel/setup_mappi2.c * * Setup routines for Renesas MAPPI-II(M3A-ZA36) Board * @@ -156,7 +156,6 @@ void __init init_IRQ(void) irq_desc[PLD_IRQ_CFIREQ].handler = &mappi2_irq_type; irq_desc[PLD_IRQ_CFIREQ].action = 0; irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ -// icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; disable_mappi2_irq(PLD_IRQ_CFIREQ); @@ -167,7 +166,6 @@ void __init init_IRQ(void) irq_desc[PLD_IRQ_CFC_INSERT].action = 0; irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; -// icu_data[PLD_IRQ_CFC_INSERT].icucr = 0; disable_mappi2_irq(PLD_IRQ_CFC_INSERT); /* ICUCR42: CFC Eject */ @@ -176,9 +174,7 @@ void __init init_IRQ(void) irq_desc[PLD_IRQ_CFC_EJECT].action = 0; irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; -// icu_data[PLD_IRQ_CFC_EJECT].icucr = 0; disable_mappi2_irq(PLD_IRQ_CFC_EJECT); - #endif /* CONFIG_MAPPI2_CFC */ } diff --git a/arch/m32r/kernel/setup_mappi3.c b/arch/m32r/kernel/setup_mappi3.c new file mode 100644 index 0000000..72b5b76 --- /dev/null +++ b/arch/m32r/kernel/setup_mappi3.c @@ -0,0 +1,208 @@ +/* + * linux/arch/m32r/kernel/setup_mappi3.c + * + * Setup routines for Renesas MAPPI-III(M3A-2170) Board + * + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long))) + +#ifndef CONFIG_SMP +typedef struct { + unsigned long icucr; /* ICU Control Register */ +} icu_data_t; +#endif /* CONFIG_SMP */ + +icu_data_t icu_data[NR_IRQS]; + +static void disable_mappi3_irq(unsigned int irq) +{ + unsigned long port, data; + + if ((irq == 0) ||(irq >= NR_IRQS)) { + printk("bad irq 0x%08x\n", irq); + return; + } + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7; + outl(data, port); +} + +static void enable_mappi3_irq(unsigned int irq) +{ + unsigned long port, data; + + if ((irq == 0) ||(irq >= NR_IRQS)) { + printk("bad irq 0x%08x\n", irq); + return; + } + port = irq2port(irq); + data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6; + outl(data, port); +} + +static void mask_and_ack_mappi3(unsigned int irq) +{ + disable_mappi3_irq(irq); +} + +static void end_mappi3_irq(unsigned int irq) +{ + enable_mappi3_irq(irq); +} + +static unsigned int startup_mappi3_irq(unsigned int irq) +{ + enable_mappi3_irq(irq); + return (0); +} + +static void shutdown_mappi3_irq(unsigned int irq) +{ + unsigned long port; + + port = irq2port(irq); + outl(M32R_ICUCR_ILEVEL7, port); +} + +static struct hw_interrupt_type mappi3_irq_type = +{ + "MAPPI3-IRQ", + startup_mappi3_irq, + shutdown_mappi3_irq, + enable_mappi3_irq, + disable_mappi3_irq, + mask_and_ack_mappi3, + end_mappi3_irq +}; + +void __init init_IRQ(void) +{ +#if defined(CONFIG_SMC91X) + /* INT0 : LAN controller (SMC91111) */ + irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT0].handler = &mappi3_irq_type; + irq_desc[M32R_IRQ_INT0].action = 0; + irq_desc[M32R_IRQ_INT0].depth = 1; + icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_mappi3_irq(M32R_IRQ_INT0); +#endif /* CONFIG_SMC91X */ + + /* MFT2 : system timer */ + irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_MFT2].handler = &mappi3_irq_type; + irq_desc[M32R_IRQ_MFT2].action = 0; + irq_desc[M32R_IRQ_MFT2].depth = 1; + icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; + disable_mappi3_irq(M32R_IRQ_MFT2); + +#ifdef CONFIG_SERIAL_M32R_SIO + /* SIO0_R : uart receive data */ + irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_R].handler = &mappi3_irq_type; + irq_desc[M32R_IRQ_SIO0_R].action = 0; + irq_desc[M32R_IRQ_SIO0_R].depth = 1; + icu_data[M32R_IRQ_SIO0_R].icucr = 0; + disable_mappi3_irq(M32R_IRQ_SIO0_R); + + /* SIO0_S : uart send data */ + irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO0_S].handler = &mappi3_irq_type; + irq_desc[M32R_IRQ_SIO0_S].action = 0; + irq_desc[M32R_IRQ_SIO0_S].depth = 1; + icu_data[M32R_IRQ_SIO0_S].icucr = 0; + disable_mappi3_irq(M32R_IRQ_SIO0_S); + /* SIO1_R : uart receive data */ + irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_R].handler = &mappi3_irq_type; + irq_desc[M32R_IRQ_SIO1_R].action = 0; + irq_desc[M32R_IRQ_SIO1_R].depth = 1; + icu_data[M32R_IRQ_SIO1_R].icucr = 0; + disable_mappi3_irq(M32R_IRQ_SIO1_R); + + /* SIO1_S : uart send data */ + irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_SIO1_S].handler = &mappi3_irq_type; + irq_desc[M32R_IRQ_SIO1_S].action = 0; + irq_desc[M32R_IRQ_SIO1_S].depth = 1; + icu_data[M32R_IRQ_SIO1_S].icucr = 0; + disable_mappi3_irq(M32R_IRQ_SIO1_S); +#endif /* CONFIG_M32R_USE_DBG_CONSOLE */ + +#if defined(CONFIG_USB) + /* INT1 : USB Host controller interrupt */ + irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED; + irq_desc[M32R_IRQ_INT1].handler = &mappi3_irq_type; + irq_desc[M32R_IRQ_INT1].action = 0; + irq_desc[M32R_IRQ_INT1].depth = 1; + icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01; + disable_mappi3_irq(M32R_IRQ_INT1); +#endif /* CONFIG_USB */ + + /* ICUCR40: CFC IREQ */ + irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFIREQ].handler = &mappi3_irq_type; + irq_desc[PLD_IRQ_CFIREQ].action = 0; + irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */ + icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; + disable_mappi3_irq(PLD_IRQ_CFIREQ); + +#if defined(CONFIG_M32R_CFC) + /* ICUCR41: CFC Insert */ + irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_INSERT].handler = &mappi3_irq_type; + irq_desc[PLD_IRQ_CFC_INSERT].action = 0; + irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */ + icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; + disable_mappi3_irq(PLD_IRQ_CFC_INSERT); + + /* ICUCR42: CFC Eject */ + irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED; + irq_desc[PLD_IRQ_CFC_EJECT].handler = &mappi3_irq_type; + irq_desc[PLD_IRQ_CFC_EJECT].action = 0; + irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */ + icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; + disable_mappi3_irq(PLD_IRQ_CFC_EJECT); +#endif /* CONFIG_M32R_CFC */ +} + +#define LAN_IOSTART 0x300 +#define LAN_IOEND 0x320 +static struct resource smc91x_resources[] = { + [0] = { + .start = (LAN_IOSTART), + .end = (LAN_IOEND), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = M32R_IRQ_INT0, + .end = M32R_IRQ_INT0, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static int __init platform_init(void) +{ + platform_device_register(&smc91x_device); + return 0; +} +arch_initcall(platform_init); diff --git a/arch/m32r/mappi3/defconfig.smp b/arch/m32r/mappi3/defconfig.smp new file mode 100644 index 0000000..2eebe75f --- /dev/null +++ b/arch/m32r/mappi3/defconfig.smp @@ -0,0 +1,751 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.12-rc5 +# Tue May 31 17:55:34 2005 +# +CONFIG_M32R=y +# CONFIG_UID16 is not set +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_HOTPLUG=y +CONFIG_KOBJECT_UEVENT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_CPUSETS is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +CONFIG_PLAT_MAPPI3=y +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=10000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x08000000 +CONFIG_NOHIGHMEM=y +CONFIG_DISCONTIGMEM=y +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00080000 +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_PREEMPT=y +# CONFIG_HAVE_DEC_LOCK is not set +CONFIG_SMP=y +# CONFIG_CHIP_M32700_TS1 is not set +CONFIG_NR_CPUS=2 +# CONFIG_NUMA is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +CONFIG_PCCARD=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA=y + +# +# PC-card bridges +# +# CONFIG_TCIC is not set +# CONFIG_M32R_PCC is not set +# CONFIG_M32R_CFC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=y +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_SMC91X=y +# CONFIG_NE2000 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +# CONFIG_SERIAL_M32R_PLDSIO is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS_FS=y +CONFIG_JFFS_FS_VERBOSE=0 +CONFIG_JFFS_PROC_FS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_JFFS2_FS_NOR_ECC is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=15 +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/arch/m32r/mappi3/dot.gdbinit b/arch/m32r/mappi3/dot.gdbinit new file mode 100644 index 0000000..89c2218 --- /dev/null +++ b/arch/m32r/mappi3/dot.gdbinit @@ -0,0 +1,224 @@ +# .gdbinit file +# $Id: dot.gdbinit,v 1.1 2005/04/11 02:21:08 sakugawa Exp $ + +# setting +set width 0d70 +set radix 0d16 +use_debug_dma + +# Initialize SDRAM controller for Mappi +define sdram_init + # SDIR0 + set *(unsigned long *)0x00ef6008 = 0x00000182 + # SDIR1 + set *(unsigned long *)0x00ef600c = 0x00000001 + # Initialize wait + shell sleep 0.1 + # MOD + set *(unsigned long *)0x00ef602c = 0x00000020 + set *(unsigned long *)0x00ef604c = 0x00000020 + # TR + set *(unsigned long *)0x00ef6028 = 0x00051502 + set *(unsigned long *)0x00ef6048 = 0x00051502 + # ADR + set *(unsigned long *)0x00ef6020 = 0x08000004 + set *(unsigned long *)0x00ef6040 = 0x0c000004 + # AutoRef On + set *(unsigned long *)0x00ef6004 = 0x00010517 + # Access enable + set *(unsigned long *)0x00ef6024 = 0x00000001 + set *(unsigned long *)0x00ef6044 = 0x00000001 +end + +# Initialize LAN controller for Mappi +define lanc_init + # Set BSEL4 + #set *(unsigned long *)0x00ef5004 = 0x0fff330f + #set *(unsigned long *)0x00ef5004 = 0x01113301 + +# set *(unsigned long *)0x00ef5004 = 0x02011101 +# set *(unsigned long *)0x00ef5004 = 0x04441104 +end + +define clock_init + set *(unsigned long *)0x00ef4010 = 2 + set *(unsigned long *)0x00ef4014 = 2 + set *(unsigned long *)0x00ef4020 = 3 + set *(unsigned long *)0x00ef4024 = 3 + set *(unsigned long *)0x00ef4004 = 0x7 +# shell sleep 0.1 +# set *(unsigned long *)0x00ef4004 = 0x5 + shell sleep 0.1 + set *(unsigned long *)0x00ef4008 = 0x0200 +end + +define port_init + set $sfrbase = 0x00ef0000 + set *(unsigned short *)0x00ef1060 = 0x5555 + set *(unsigned short *)0x00ef1062 = 0x5555 + set *(unsigned short *)0x00ef1064 = 0x5555 + set *(unsigned short *)0x00ef1066 = 0x5555 + set *(unsigned short *)0x00ef1068 = 0x5555 + set *(unsigned short *)0x00ef106a = 0x0000 + set *(unsigned short *)0x00ef106e = 0x5555 + set *(unsigned short *)0x00ef1070 = 0x5555 +end + +# MMU enable +define mmu_enable + set $evb=0x88000000 + set *(unsigned long *)0xffff0024=1 +end + +# MMU disable +define mmu_disable + set $evb=0 + set *(unsigned long *)0xffff0024=0 +end + +# Show TLB entries +define show_tlb_entries + set $i = 0 + set $addr = $arg0 + while ($i < 0d16 ) + set $tlb_tag = *(unsigned long*)$addr + set $tlb_data = *(unsigned long*)($addr + 4) + printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data + set $i = $i + 1 + set $addr = $addr + 8 + end +end +define itlb + set $itlb=0xfe000000 + show_tlb_entries $itlb +end +define dtlb + set $dtlb=0xfe000800 + show_tlb_entries $dtlb +end + +# Cache ON +define set_cache_type + set $mctype = (void*)0xfffffff8 +# chaos +# set *(unsigned long *)($mctype) = 0x0000c000 +# m32102 i-cache only + set *(unsigned long *)($mctype) = 0x00008000 +# m32102 d-cache only +# set *(unsigned long *)($mctype) = 0x00004000 +end +define cache_on + set $param = (void*)0x08001000 + set *(unsigned long *)($param) = 0x60ff6102 +end + + +# Show current task structure +define show_current + set $current = $spi & 0xffffe000 + printf "$current=0x%08lX\n",$current + print *(struct task_struct *)$current +end + +# Show user assigned task structure +define show_task + set $task = $arg0 & 0xffffe000 + printf "$task=0x%08lX\n",$task + print *(struct task_struct *)$task +end +document show_task + Show user assigned task structure + arg0 : task structure address +end + +# Show M32R registers +define show_regs + printf " R0[0x%08lX] R1[0x%08lX] R2[0x%08lX] R3[0x%08lX]\n",$r0,$r1,$r2,$r3 + printf " R4[0x%08lX] R5[0x%08lX] R6[0x%08lX] R7[0x%08lX]\n",$r4,$r5,$r6,$r7 + printf " R8[0x%08lX] R9[0x%08lX] R10[0x%08lX] R11[0x%08lX]\n",$r8,$r9,$r10,$r11 + printf "R12[0x%08lX] FP[0x%08lX] LR[0x%08lX] SP[0x%08lX]\n",$r12,$fp,$lr,$sp + printf "PSW[0x%08lX] CBR[0x%08lX] SPI[0x%08lX] SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu + printf "BPC[0x%08lX] PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch + printf "EVB[0x%08lX]\n",$evb + + set $mests = *(unsigned long *)0xffff000c + set $mdeva = *(unsigned long *)0xffff0010 + printf "MESTS[0x%08lX] MDEVA[0x%08lX]\n",$mests,$mdeva +end + + +# Setup all +define setup + clock_init + shell sleep 0.1 + port_init + sdram_init +# lanc_init +# dispc_init +# set $evb=0x08000000 +end + +# Load modules +define load_modules + use_debug_dma + load +# load busybox.mot +end + +# Set kernel parameters +define set_kernel_parameters + set $param = (void*)0x08001000 + + ## MOUNT_ROOT_RDONLY + set {long}($param+0x00)=0 + ## RAMDISK_FLAGS + #set {long}($param+0x04)=0 + ## ORIG_ROOT_DEV + #set {long}($param+0x08)=0x00000100 + ## LOADER_TYPE + #set {long}($param+0x0C)=0 + ## INITRD_START + set {long}($param+0x10)=0x082a0000 + ## INITRD_SIZE + set {long}($param+0x14)=0d6200000 + + # M32R_CPUCLK + set *(unsigned long *)($param + 0x0018) = 0d100000000 + # M32R_BUSCLK + set *(unsigned long *)($param + 0x001c) = 0d50000000 + # M32R_TIMER_DIVIDE + set *(unsigned long *)($param + 0x0020) = 0d128 + + + set {char[0x200]}($param + 0x100) = "console=ttyS0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.2.6_04 nfsaddrs=192.168.0.102:192.168.0.1:192.168.0.1:255.255.255.0:mappi: \0" + + +end + +# Boot +define boot + set_kernel_parameters + debug_chaos + set *(unsigned long *)0x00f00000=0x08002000 + set $pc=0x08002000 + set $fp=0 + del b + si +end + +# Restart +define restart + sdireset + sdireset + setup + load_modules + boot +end + +sdireset +sdireset +file vmlinux +target m32rsdi + +restart +boot diff --git a/include/asm-m32r/ide.h b/include/asm-m32r/ide.h index be64f24..194393b 100644 --- a/include/asm-m32r/ide.h +++ b/include/asm-m32r/ide.h @@ -35,7 +35,7 @@ static __inline__ int ide_default_irq(unsigned long base) { switch (base) { -#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) +#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3) case 0x1f0: return PLD_IRQ_CFIREQ; default: return 0; diff --git a/include/asm-m32r/m32102.h b/include/asm-m32r/m32102.h index b560340..cb98101 100644 --- a/include/asm-m32r/m32102.h +++ b/include/asm-m32r/m32102.h @@ -175,6 +175,7 @@ #define M32R_ICU_CR5_PORTL (0x210+M32R_ICU_OFFSET) /* INT4 */ #define M32R_ICU_CR6_PORTL (0x214+M32R_ICU_OFFSET) /* INT5 */ #define M32R_ICU_CR7_PORTL (0x218+M32R_ICU_OFFSET) /* INT6 */ +#define M32R_ICU_CR8_PORTL (0x219+M32R_ICU_OFFSET) /* INT7 */ #define M32R_ICU_CR16_PORTL (0x23C+M32R_ICU_OFFSET) /* MFT0 */ #define M32R_ICU_CR17_PORTL (0x240+M32R_ICU_OFFSET) /* MFT1 */ #define M32R_ICU_CR18_PORTL (0x244+M32R_ICU_OFFSET) /* MFT2 */ diff --git a/include/asm-m32r/m32r.h b/include/asm-m32r/m32r.h index f116649..fd2b282 100644 --- a/include/asm-m32r/m32r.h +++ b/include/asm-m32r/m32r.h @@ -36,6 +36,10 @@ #include #endif /* CONFIG_PLAT_MAPPI2 */ +#if defined(CONFIG_PLAT_MAPPI3) +#include +#endif /* CONFIG_PLAT_MAPPI3 */ + #if defined(CONFIG_PLAT_USRV) #include #endif diff --git a/include/asm-m32r/mappi3/mappi3_pld.h b/include/asm-m32r/mappi3/mappi3_pld.h new file mode 100644 index 0000000..3f1551f --- /dev/null +++ b/include/asm-m32r/mappi3/mappi3_pld.h @@ -0,0 +1,143 @@ +/* + * include/asm/mappi3/mappi3_pld.h + * + * Definitions for Extended IO Logic on MAPPI3 board. + * based on m32700ut_pld.h + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + * + */ + +#ifndef _MAPPI3_PLD_H +#define _MAPPI3_PLD_H + +#ifndef __ASSEMBLY__ +/* FIXME: + * Some C functions use non-cache address, so can't define non-cache address. + */ +#define PLD_BASE (0x1c000000 /* + NONCACHE_OFFSET */) +#define __reg8 (volatile unsigned char *) +#define __reg16 (volatile unsigned short *) +#define __reg32 (volatile unsigned int *) +#else +#define PLD_BASE (0x1c000000 + NONCACHE_OFFSET) +#define __reg8 +#define __reg16 +#define __reg32 +#endif /* __ASSEMBLY__ */ + +/* CFC */ +#define PLD_CFRSTCR __reg16(PLD_BASE + 0x0000) +#define PLD_CFSTS __reg16(PLD_BASE + 0x0002) +#define PLD_CFIMASK __reg16(PLD_BASE + 0x0004) +#define PLD_CFBUFCR __reg16(PLD_BASE + 0x0006) +#define PLD_CFCR0 __reg16(PLD_BASE + 0x000a) +#define PLD_CFCR1 __reg16(PLD_BASE + 0x000c) + +/* MMC */ +#define PLD_MMCCR __reg16(PLD_BASE + 0x4000) +#define PLD_MMCMOD __reg16(PLD_BASE + 0x4002) +#define PLD_MMCSTS __reg16(PLD_BASE + 0x4006) +#define PLD_MMCBAUR __reg16(PLD_BASE + 0x400a) +#define PLD_MMCCMDBCUT __reg16(PLD_BASE + 0x400c) +#define PLD_MMCCDTBCUT __reg16(PLD_BASE + 0x400e) +#define PLD_MMCDET __reg16(PLD_BASE + 0x4010) +#define PLD_MMCWP __reg16(PLD_BASE + 0x4012) +#define PLD_MMCWDATA __reg16(PLD_BASE + 0x5000) +#define PLD_MMCRDATA __reg16(PLD_BASE + 0x6000) +#define PLD_MMCCMDDATA __reg16(PLD_BASE + 0x7000) +#define PLD_MMCRSPDATA __reg16(PLD_BASE + 0x7006) + +/* Power Control of MMC and CF */ +#define PLD_CPCR __reg16(PLD_BASE + 0x14000) + + +/*==== ICU ====*/ +#define M32R_IRQ_PC104 (5) /* INT4(PC/104) */ +#define M32R_IRQ_I2C (28) /* I2C-BUS */ +#define PLD_IRQ_CFIREQ (6) /* INT5 CFC Card Interrupt */ +#define PLD_IRQ_CFC_INSERT (7) /* INT6 CFC Card Insert */ +#define PLD_IRQ_CFC_EJECT (8) /* INT7 CFC Card Eject */ +#define PLD_IRQ_MMCCARD (43) /* MMC Card Insert */ +#define PLD_IRQ_MMCIRQ (44) /* MMC Transfer Done */ + + +#if 0 +/* LED Control + * + * 1: DIP swich side + * 2: Reset switch side + */ +#define PLD_IOLEDCR __reg16(PLD_BASE + 0x14002) +#define PLD_IOLED_1_ON 0x001 +#define PLD_IOLED_1_OFF 0x000 +#define PLD_IOLED_2_ON 0x002 +#define PLD_IOLED_2_OFF 0x000 + +/* DIP Switch + * 0: Write-protect of Flash Memory (0:protected, 1:non-protected) + * 1: - + * 2: - + * 3: - + */ +#define PLD_IOSWSTS __reg16(PLD_BASE + 0x14004) +#define PLD_IOSWSTS_IOSW2 0x0200 +#define PLD_IOSWSTS_IOSW1 0x0100 +#define PLD_IOSWSTS_IOWP0 0x0001 + +#endif + +/* CRC */ +#define PLD_CRC7DATA __reg16(PLD_BASE + 0x18000) +#define PLD_CRC7INDATA __reg16(PLD_BASE + 0x18002) +#define PLD_CRC16DATA __reg16(PLD_BASE + 0x18004) +#define PLD_CRC16INDATA __reg16(PLD_BASE + 0x18006) +#define PLD_CRC16ADATA __reg16(PLD_BASE + 0x18008) +#define PLD_CRC16AINDATA __reg16(PLD_BASE + 0x1800a) + + +#if 0 +/* RTC */ +#define PLD_RTCCR __reg16(PLD_BASE + 0x1c000) +#define PLD_RTCBAUR __reg16(PLD_BASE + 0x1c002) +#define PLD_RTCWRDATA __reg16(PLD_BASE + 0x1c004) +#define PLD_RTCRDDATA __reg16(PLD_BASE + 0x1c006) +#define PLD_RTCRSTODT __reg16(PLD_BASE + 0x1c008) + +/* SIO0 */ +#define PLD_ESIO0CR __reg16(PLD_BASE + 0x20000) +#define PLD_ESIO0CR_TXEN 0x0001 +#define PLD_ESIO0CR_RXEN 0x0002 +#define PLD_ESIO0MOD0 __reg16(PLD_BASE + 0x20002) +#define PLD_ESIO0MOD0_CTSS 0x0040 +#define PLD_ESIO0MOD0_RTSS 0x0080 +#define PLD_ESIO0MOD1 __reg16(PLD_BASE + 0x20004) +#define PLD_ESIO0MOD1_LMFS 0x0010 +#define PLD_ESIO0STS __reg16(PLD_BASE + 0x20006) +#define PLD_ESIO0STS_TEMP 0x0001 +#define PLD_ESIO0STS_TXCP 0x0002 +#define PLD_ESIO0STS_RXCP 0x0004 +#define PLD_ESIO0STS_TXSC 0x0100 +#define PLD_ESIO0STS_RXSC 0x0200 +#define PLD_ESIO0STS_TXREADY (PLD_ESIO0STS_TXCP | PLD_ESIO0STS_TEMP) +#define PLD_ESIO0INTCR __reg16(PLD_BASE + 0x20008) +#define PLD_ESIO0INTCR_TXIEN 0x0002 +#define PLD_ESIO0INTCR_RXCEN 0x0004 +#define PLD_ESIO0BAUR __reg16(PLD_BASE + 0x2000a) +#define PLD_ESIO0TXB __reg16(PLD_BASE + 0x2000c) +#define PLD_ESIO0RXB __reg16(PLD_BASE + 0x2000e) + +/* SIM Card */ +#define PLD_SCCR __reg16(PLD_BASE + 0x38000) +#define PLD_SCMOD __reg16(PLD_BASE + 0x38004) +#define PLD_SCSTS __reg16(PLD_BASE + 0x38006) +#define PLD_SCINTCR __reg16(PLD_BASE + 0x38008) +#define PLD_SCBAUR __reg16(PLD_BASE + 0x3800a) +#define PLD_SCTXB __reg16(PLD_BASE + 0x3800c) +#define PLD_SCRXB __reg16(PLD_BASE + 0x3800e) + +#endif + +#endif /* _MAPPI3_PLD.H */ -- cgit v0.10.2 From 6f973b001a9b511900fb73d816adf77d8755838c Mon Sep 17 00:00:00 2001 From: Hirokazu Takata Date: Tue, 21 Jun 2005 17:16:13 -0700 Subject: [PATCH] m32r: Update setup_xxxxx.c Change coding styles of hw_interrupt_type struct's initialization portions. Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c index 488aa87..b014e2c 100644 --- a/arch/m32r/kernel/setup_m32700ut.c +++ b/arch/m32r/kernel/setup_m32700ut.c @@ -78,13 +78,13 @@ static void shutdown_m32700ut_irq(unsigned int irq) static struct hw_interrupt_type m32700ut_irq_type = { - "M32700UT-IRQ", - startup_m32700ut_irq, - shutdown_m32700ut_irq, - enable_m32700ut_irq, - disable_m32700ut_irq, - mask_and_ack_m32700ut, - end_m32700ut_irq + .typename = "M32700UT-IRQ", + .startup = startup_m32700ut_irq, + .shutdown = shutdown_m32700ut_irq, + .enable = enable_m32700ut_irq, + .disable = disable_m32700ut_irq, + .ack = mask_and_ack_m32700ut, + .end = end_m32700ut_irq }; /* @@ -155,13 +155,13 @@ static void shutdown_m32700ut_pld_irq(unsigned int irq) static struct hw_interrupt_type m32700ut_pld_irq_type = { - "M32700UT-PLD-IRQ", - startup_m32700ut_pld_irq, - shutdown_m32700ut_pld_irq, - enable_m32700ut_pld_irq, - disable_m32700ut_pld_irq, - mask_and_ack_m32700ut_pld, - end_m32700ut_pld_irq + .typename = "M32700UT-PLD-IRQ", + .startup = startup_m32700ut_pld_irq, + .shutdown = shutdown_m32700ut_pld_irq, + .enable = enable_m32700ut_pld_irq, + .disable = disable_m32700ut_pld_irq, + .ack = mask_and_ack_m32700ut_pld, + .end = end_m32700ut_pld_irq }; /* @@ -224,13 +224,13 @@ static void shutdown_m32700ut_lanpld_irq(unsigned int irq) static struct hw_interrupt_type m32700ut_lanpld_irq_type = { - "M32700UT-PLD-LAN-IRQ", - startup_m32700ut_lanpld_irq, - shutdown_m32700ut_lanpld_irq, - enable_m32700ut_lanpld_irq, - disable_m32700ut_lanpld_irq, - mask_and_ack_m32700ut_lanpld, - end_m32700ut_lanpld_irq + .typename = "M32700UT-PLD-LAN-IRQ", + .startup = startup_m32700ut_lanpld_irq, + .shutdown = shutdown_m32700ut_lanpld_irq, + .enable = enable_m32700ut_lanpld_irq, + .disable = disable_m32700ut_lanpld_irq, + .ack = mask_and_ack_m32700ut_lanpld, + .end = end_m32700ut_lanpld_irq }; /* @@ -293,13 +293,13 @@ static void shutdown_m32700ut_lcdpld_irq(unsigned int irq) static struct hw_interrupt_type m32700ut_lcdpld_irq_type = { - "M32700UT-PLD-LCD-IRQ", - startup_m32700ut_lcdpld_irq, - shutdown_m32700ut_lcdpld_irq, - enable_m32700ut_lcdpld_irq, - disable_m32700ut_lcdpld_irq, - mask_and_ack_m32700ut_lcdpld, - end_m32700ut_lcdpld_irq + .typename = "M32700UT-PLD-LCD-IRQ", + .startup = startup_m32700ut_lcdpld_irq, + .shutdown = shutdown_m32700ut_lcdpld_irq, + .enable = enable_m32700ut_lcdpld_irq, + .disable = disable_m32700ut_lcdpld_irq, + .ack = mask_and_ack_m32700ut_lcdpld, + .end = end_m32700ut_lcdpld_irq }; void __init init_IRQ(void) diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c index 1e74110..aaf8e56 100644 --- a/arch/m32r/kernel/setup_mappi.c +++ b/arch/m32r/kernel/setup_mappi.c @@ -70,13 +70,13 @@ static void shutdown_mappi_irq(unsigned int irq) static struct hw_interrupt_type mappi_irq_type = { - "MAPPI-IRQ", - startup_mappi_irq, - shutdown_mappi_irq, - enable_mappi_irq, - disable_mappi_irq, - mask_and_ack_mappi, - end_mappi_irq + .typename = "MAPPI-IRQ", + .startup = startup_mappi_irq, + .shutdown = shutdown_mappi_irq, + .enable = enable_mappi_irq, + .disable = disable_mappi_irq, + .ack = mask_and_ack_mappi, + .end = end_mappi_irq }; void __init init_IRQ(void) diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c index 248fc65..38d5e9a 100644 --- a/arch/m32r/kernel/setup_mappi2.c +++ b/arch/m32r/kernel/setup_mappi2.c @@ -79,13 +79,13 @@ static void shutdown_mappi2_irq(unsigned int irq) static struct hw_interrupt_type mappi2_irq_type = { - "MAPPI2-IRQ", - startup_mappi2_irq, - shutdown_mappi2_irq, - enable_mappi2_irq, - disable_mappi2_irq, - mask_and_ack_mappi2, - end_mappi2_irq + .typename = "MAPPI2-IRQ", + .startup = startup_mappi2_irq, + .shutdown = shutdown_mappi2_irq, + .enable = enable_mappi2_irq, + .disable = disable_mappi2_irq, + .ack = mask_and_ack_mappi2, + .end = end_mappi2_irq }; void __init init_IRQ(void) diff --git a/arch/m32r/kernel/setup_mappi3.c b/arch/m32r/kernel/setup_mappi3.c index 72b5b76..3d60a85 100644 --- a/arch/m32r/kernel/setup_mappi3.c +++ b/arch/m32r/kernel/setup_mappi3.c @@ -79,13 +79,13 @@ static void shutdown_mappi3_irq(unsigned int irq) static struct hw_interrupt_type mappi3_irq_type = { - "MAPPI3-IRQ", - startup_mappi3_irq, - shutdown_mappi3_irq, - enable_mappi3_irq, - disable_mappi3_irq, - mask_and_ack_mappi3, - end_mappi3_irq + .typename = "MAPPI3-IRQ", + .startup = startup_mappi3_irq, + .shutdown = shutdown_mappi3_irq, + .enable = enable_mappi3_irq, + .disable = disable_mappi3_irq, + .ack = mask_and_ack_mappi3, + .end = end_mappi3_irq }; void __init init_IRQ(void) diff --git a/arch/m32r/kernel/setup_oaks32r.c b/arch/m32r/kernel/setup_oaks32r.c index b048345..d656640 100644 --- a/arch/m32r/kernel/setup_oaks32r.c +++ b/arch/m32r/kernel/setup_oaks32r.c @@ -70,13 +70,13 @@ static void shutdown_oaks32r_irq(unsigned int irq) static struct hw_interrupt_type oaks32r_irq_type = { - "OAKS32R-IRQ", - startup_oaks32r_irq, - shutdown_oaks32r_irq, - enable_oaks32r_irq, - disable_oaks32r_irq, - mask_and_ack_mappi, - end_oaks32r_irq + .typename = "OAKS32R-IRQ", + .startup = startup_oaks32r_irq, + .shutdown = shutdown_oaks32r_irq, + .enable = enable_oaks32r_irq, + .disable = disable_oaks32r_irq, + .ack = mask_and_ack_mappi, + .end = end_oaks32r_irq }; void __init init_IRQ(void) diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c index 84315e3..86f4cf2 100644 --- a/arch/m32r/kernel/setup_opsput.c +++ b/arch/m32r/kernel/setup_opsput.c @@ -79,13 +79,13 @@ static void shutdown_opsput_irq(unsigned int irq) static struct hw_interrupt_type opsput_irq_type = { - "OPSPUT-IRQ", - startup_opsput_irq, - shutdown_opsput_irq, - enable_opsput_irq, - disable_opsput_irq, - mask_and_ack_opsput, - end_opsput_irq + .typename = "OPSPUT-IRQ", + .startup = startup_opsput_irq, + .shutdown = shutdown_opsput_irq, + .enable = enable_opsput_irq, + .disable = disable_opsput_irq, + .ack = mask_and_ack_opsput, + .end = end_opsput_irq }; /* @@ -156,13 +156,13 @@ static void shutdown_opsput_pld_irq(unsigned int irq) static struct hw_interrupt_type opsput_pld_irq_type = { - "OPSPUT-PLD-IRQ", - startup_opsput_pld_irq, - shutdown_opsput_pld_irq, - enable_opsput_pld_irq, - disable_opsput_pld_irq, - mask_and_ack_opsput_pld, - end_opsput_pld_irq + .typename = "OPSPUT-PLD-IRQ", + .startup = startup_opsput_pld_irq, + .shutdown = shutdown_opsput_pld_irq, + .enable = enable_opsput_pld_irq, + .disable = disable_opsput_pld_irq, + .ack = mask_and_ack_opsput_pld, + .end = end_opsput_pld_irq }; /* diff --git a/arch/m32r/kernel/setup_usrv.c b/arch/m32r/kernel/setup_usrv.c index fe417be..634741b 100644 --- a/arch/m32r/kernel/setup_usrv.c +++ b/arch/m32r/kernel/setup_usrv.c @@ -70,13 +70,13 @@ static void shutdown_mappi_irq(unsigned int irq) static struct hw_interrupt_type mappi_irq_type = { - "M32700-IRQ", - startup_mappi_irq, - shutdown_mappi_irq, - enable_mappi_irq, - disable_mappi_irq, - mask_and_ack_mappi, - end_mappi_irq + .typename = "M32700-IRQ", + .startup = startup_mappi_irq, + .shutdown = shutdown_mappi_irq, + .enable = enable_mappi_irq, + .disable = disable_mappi_irq, + .ack = mask_and_ack_mappi, + .end = end_mappi_irq }; /* @@ -143,13 +143,13 @@ static void shutdown_m32700ut_pld_irq(unsigned int irq) static struct hw_interrupt_type m32700ut_pld_irq_type = { - "USRV-PLD-IRQ", - startup_m32700ut_pld_irq, - shutdown_m32700ut_pld_irq, - enable_m32700ut_pld_irq, - disable_m32700ut_pld_irq, - mask_and_ack_m32700ut_pld, - end_m32700ut_pld_irq + .typename = "USRV-PLD-IRQ", + .startup = startup_m32700ut_pld_irq, + .shutdown = shutdown_m32700ut_pld_irq, + .enable = enable_m32700ut_pld_irq, + .disable = disable_m32700ut_pld_irq, + .ack = mask_and_ack_m32700ut_pld, + .end = end_m32700ut_pld_irq }; void __init init_IRQ(void) -- cgit v0.10.2 From 934bb7f88eb398f62314fa63ba72ac6dcd21192a Mon Sep 17 00:00:00 2001 From: Hirokazu Takata Date: Tue, 21 Jun 2005 17:16:14 -0700 Subject: [PATCH] m32r: Update m32r_cfc.[ch] to support Mappi-III platform This patch is for the M32R CF/PCMCIA drivers to support a new platform, Mappi-III evaluation board. Signed-off-by: Mamoru Sakugawa Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 6375ebc..14e4124 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -171,19 +171,21 @@ config PCMCIA_PROBE config M32R_PCC bool "M32R PCMCIA I/F" depends on M32R && CHIP_M32700 && PCMCIA + select PCCARD_NONSTATIC help Say Y here to use the M32R PCMCIA controller. config M32R_CFC bool "M32R CF I/F Controller" - depends on M32R && (PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_OPSPUT) + depends on M32R && (PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_MAPPI3 || PLAT_OPSPUT) + select PCCARD_NONSTATIC help Say Y here to use the M32R CompactFlash controller. config M32R_CFC_NUM int "M32R CF I/F number" depends on M32R_CFC - default "1" if PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_OPSPUT + default "1" if PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_MAPPI3 || PLAT_OPSPUT help Set the number of M32R CF slots. diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 581bfa9..b1111c6 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -24,9 +24,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -444,7 +444,7 @@ static int _pcc_get_status(u_short sock, u_int *value) debug(3, "m32r_cfc: _pcc_get_status: " "power off (CPCR=0x%08x)\n", status); } -#elif defined(CONFIG_PLAT_MAPPI2) +#elif defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3) if ( status ) { status = pcc_get(sock, (unsigned int)PLD_CPCR); if (status == 0) { /* power off */ @@ -452,18 +452,23 @@ static int _pcc_get_status(u_short sock, u_int *value) pcc_set(sock, (unsigned int)PLD_CFBUFCR,0); /* force buffer off for ZA-36 */ udelay(50); } - status = pcc_get(sock, (unsigned int)PLD_CFBUFCR); - if (status != 0) { /* buffer off */ - pcc_set(sock, (unsigned int)PLD_CFBUFCR,0); - udelay(50); - pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0101); - udelay(25); /* for IDE reset */ - pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0100); - mdelay(2); /* for IDE reset */ - } else { - *value |= SS_POWERON; - *value |= SS_READY; - } + *value |= SS_POWERON; + + pcc_set(sock, (unsigned int)PLD_CFBUFCR,0); + udelay(50); + pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0101); + udelay(25); /* for IDE reset */ + pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0100); + mdelay(2); /* for IDE reset */ + + *value |= SS_READY; + *value |= SS_3VCARD; + } else { + /* disable CF power */ + pcc_set(sock, (unsigned int)PLD_CPCR, 0); + udelay(100); + debug(3, "m32r_cfc: _pcc_get_status: " + "power off (CPCR=0x%08x)\n", status); } #else #error no platform configuration @@ -479,14 +484,13 @@ static int _pcc_get_socket(u_short sock, socket_state_t *state) { // pcc_socket_t *t = &socket[sock]; -#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) state->flags = 0; state->csc_mask = SS_DETECT; state->csc_mask |= SS_READY; state->io_irq = 0; state->Vcc = 33; /* 3.3V fixed */ state->Vpp = 33; -#endif + debug(3, "m32r_cfc: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); @@ -497,32 +501,17 @@ static int _pcc_get_socket(u_short sock, socket_state_t *state) static int _pcc_set_socket(u_short sock, socket_state_t *state) { -#if defined(CONFIG_PLAT_MAPPI2) - u_long reg = 0; -#endif debug(3, "m32r_cfc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); -#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) +#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3) if (state->Vcc) { if ((state->Vcc != 50) && (state->Vcc != 33)) return -EINVAL; /* accept 5V and 3.3V */ } -#elif defined(CONFIG_PLAT_MAPPI2) - if (state->Vcc) { - /* - * 5V only - */ - if (state->Vcc == 50) { - reg |= PCCSIGCR_VEN; - } else { - return -EINVAL; - } - } #endif - if (state->flags & SS_RESET) { debug(3, ":RESET\n"); pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x101); @@ -788,7 +777,7 @@ static int __init init_m32r_pcc(void) return ret; } -#if defined(CONFIG_PLAT_MAPPI2) +#if defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3) pcc_set(0, (unsigned int)PLD_CFCR0, 0x0f0f); pcc_set(0, (unsigned int)PLD_CFCR1, 0x0200); #endif @@ -825,7 +814,7 @@ static int __init init_m32r_pcc(void) for (i = 0 ; i < pcc_sockets ; i++) { socket[i].socket.dev.dev = &pcc_device.dev; socket[i].socket.ops = &pcc_operations; - socket[i].socket.resource_ops = &pccard_static_ops; + socket[i].socket.resource_ops = &pccard_nonstatic_ops; socket[i].socket.owner = THIS_MODULE; socket[i].number = i; ret = pcmcia_register_socket(&socket[i].socket); diff --git a/drivers/pcmcia/m32r_cfc.h b/drivers/pcmcia/m32r_cfc.h index 17c1db7..8146e3b 100644 --- a/drivers/pcmcia/m32r_cfc.h +++ b/drivers/pcmcia/m32r_cfc.h @@ -71,11 +71,15 @@ #define CFC_IOPORT_BASE 0x1000 -#if !defined(CONFIG_PLAT_USRV) +#if defined(CONFIG_PLAT_MAPPI3) +#define CFC_ATTR_MAPBASE 0x14014000 +#define CFC_IO_MAPBASE_BYTE 0xb4012000 +#define CFC_IO_MAPBASE_WORD 0xb4002000 +#elif !defined(CONFIG_PLAT_USRV) #define CFC_ATTR_MAPBASE 0x0c014000 #define CFC_IO_MAPBASE_BYTE 0xac012000 #define CFC_IO_MAPBASE_WORD 0xac002000 -#else /* CONFIG_PLAT_USRV */ +#else #define CFC_ATTR_MAPBASE 0x04014000 #define CFC_IO_MAPBASE_BYTE 0xa4012000 #define CFC_IO_MAPBASE_WORD 0xa4002000 -- cgit v0.10.2 From 1cc1265e9a8579be0029cd675ec22a6151893e04 Mon Sep 17 00:00:00 2001 From: Hirokazu Takata Date: Tue, 21 Jun 2005 17:16:15 -0700 Subject: [PATCH] m32r: Cleanup arch/m32r/mm/extable.c Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/m32r/mm/extable.c b/arch/m32r/mm/extable.c index 9a97363..1743f23 100644 --- a/arch/m32r/mm/extable.c +++ b/arch/m32r/mm/extable.c @@ -1,10 +1,8 @@ /* - * linux/arch/i386/mm/extable.c + * linux/arch/m32r/mm/extable.c */ -#include #include -#include #include int fixup_exception(struct pt_regs *regs) @@ -19,4 +17,3 @@ int fixup_exception(struct pt_regs *regs) return 0; } - -- cgit v0.10.2 From 0adbb44a146d6dff3f74ea7a9d3826f8942ed709 Mon Sep 17 00:00:00 2001 From: Hirokazu Takata Date: Tue, 21 Jun 2005 17:16:16 -0700 Subject: [PATCH] m32r: Remove include/asm-m32r/m32102peri.h This patch removes an obsolete header file include/asm-m32r/m32102peri.h. In this header, there are some undesirable single character types, like V. And the header is almost no longer used. Signed-off-by: Hayato Fujiwara Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/net/8390.c b/drivers/net/8390.c index bab16bc..6d76f3a 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -225,9 +225,9 @@ void ei_tx_timeout(struct net_device *dev) unsigned long icucr; local_irq_save(flags); - icucr = inl(ICUCR1); + icucr = inl(M32R_ICU_CR1_PORTL); icucr |= M32R_ICUCR_ISMOD11; - outl(icucr, ICUCR1); + outl(icucr, M32R_ICU_CR1_PORTL); local_irq_restore(flags); #endif ei_local->stat.tx_errors++; diff --git a/include/asm-m32r/m32102peri.h b/include/asm-m32r/m32102peri.h deleted file mode 100644 index 3c12955..0000000 --- a/include/asm-m32r/m32102peri.h +++ /dev/null @@ -1,468 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000,2001 by Hiroyuki Kondo - */ - -#ifndef __ASSEMBLY__ - -typedef void V; -typedef char B; -typedef short S; -typedef int W; -typedef long L; -typedef float F; -typedef double D; -typedef unsigned char UB; -typedef unsigned short US; -typedef unsigned int UW; -typedef unsigned long UL; -typedef const unsigned int CUW; - -/********************************* - -M32102 ICU - -*********************************/ -#define ICUISTS (UW *)0xa0EFF004 -#define ICUIREQ0 (UW *)0xa0EFF008 -#define ICUIREQ1 (UW *)0xa0EFF00C - -#define ICUSBICR (UW *)0xa0EFF018 -#define ICUIMASK (UW *)0xa0EFF01C - -#define ICUCR1 (UW *)0xa0EFF200 /* INT0 */ -#define ICUCR2 (UW *)0xa0EFF204 /* INT1 */ -#define ICUCR3 (UW *)0xa0EFF208 /* INT2 */ -#define ICUCR4 (UW *)0xa0EFF20C /* INT3 */ -#define ICUCR5 (UW *)0xa0EFF210 /* INT4 */ -#define ICUCR6 (UW *)0xa0EFF214 /* INT5 */ -#define ICUCR7 (UW *)0xa0EFF218 /* INT6 */ - -#define ICUCR16 (UW *)0xa0EFF23C /* MFT0 */ -#define ICUCR17 (UW *)0xa0EFF240 /* MFT1 */ -#define ICUCR18 (UW *)0xa0EFF244 /* MFT2 */ -#define ICUCR19 (UW *)0xa0EFF248 /* MFT3 */ -#define ICUCR20 (UW *)0xa0EFF24C /* MFT4 */ -#define ICUCR21 (UW *)0xa0EFF250 /* MFT5 */ - -#define ICUCR32 (UW *)0xa0EFF27C /* DMA0 */ -#define ICUCR33 (UW *)0xa0EFF280 /* DMA1 */ - -#define ICUCR48 (UW *)0xa0EFF2BC /* SIO0R */ -#define ICUCR49 (UW *)0xa0EFF2C0 /* SIO0S */ -#define ICUCR50 (UW *)0xa0EFF2C4 /* SIO1R */ -#define ICUCR51 (UW *)0xa0EFF2C8 /* SIO1S */ -#define ICUCR52 (UW *)0xa0EFF2CC /* SIO2R */ -#define ICUCR53 (UW *)0xa0EFF2D0 /* SIO2S */ -#define ICUCR54 (UW *)0xa0EFF2D4 /* SIO3R */ -#define ICUCR55 (UW *)0xa0EFF2D8 /* SIO3S */ -#define ICUCR56 (UW *)0xa0EFF2DC /* SIO4R */ -#define ICUCR57 (UW *)0xa0EFF2E0 /* SIO4S */ - -/********************************* - -M32102 MFT - -*********************************/ -#define MFTCR (US *)0xa0EFC002 -#define MFTRPR (UB *)0xa0EFC006 - -#define MFT0MOD (US *)0xa0EFC102 -#define MFT0BOS (US *)0xa0EFC106 -#define MFT0CUT (US *)0xa0EFC10A -#define MFT0RLD (US *)0xa0EFC10E -#define MFT0CRLD (US *)0xa0EFC112 - -#define MFT1MOD (US *)0xa0EFC202 -#define MFT1BOS (US *)0xa0EFC206 -#define MFT1CUT (US *)0xa0EFC20A -#define MFT1RLD (US *)0xa0EFC20E -#define MFT1CRLD (US *)0xa0EFC212 - -#define MFT2MOD (US *)0xa0EFC302 -#define MFT2BOS (US *)0xa0EFC306 -#define MFT2CUT (US *)0xa0EFC30A -#define MFT2RLD (US *)0xa0EFC30E -#define MFT2CRLD (US *)0xa0EFC312 - -#define MFT3MOD (US *)0xa0EFC402 -#define MFT3CUT (US *)0xa0EFC40A -#define MFT3RLD (US *)0xa0EFC40E -#define MFT3CRLD (US *)0xa0EFC412 - -#define MFT4MOD (US *)0xa0EFC502 -#define MFT4CUT (US *)0xa0EFC50A -#define MFT4RLD (US *)0xa0EFC50E -#define MFT4CRLD (US *)0xa0EFC512 - -#define MFT5MOD (US *)0xa0EFC602 -#define MFT5CUT (US *)0xa0EFC60A -#define MFT5RLD (US *)0xa0EFC60E -#define MFT5CRLD (US *)0xa0EFC612 - -/********************************* - -M32102 SIO - -*********************************/ - -#define SIO0CR (volatile int *)0xa0efd000 -#define SIO0MOD0 (volatile int *)0xa0efd004 -#define SIO0MOD1 (volatile int *)0xa0efd008 -#define SIO0STS (volatile int *)0xa0efd00c -#define SIO0IMASK (volatile int *)0xa0efd010 -#define SIO0BAUR (volatile int *)0xa0efd014 -#define SIO0RBAUR (volatile int *)0xa0efd018 -#define SIO0TXB (volatile int *)0xa0efd01c -#define SIO0RXB (volatile int *)0xa0efd020 - -#define SIO1CR (volatile int *)0xa0efd100 -#define SIO1MOD0 (volatile int *)0xa0efd104 -#define SIO1MOD1 (volatile int *)0xa0efd108 -#define SIO1STS (volatile int *)0xa0efd10c -#define SIO1IMASK (volatile int *)0xa0efd110 -#define SIO1BAUR (volatile int *)0xa0efd114 -#define SIO1RBAUR (volatile int *)0xa0efd118 -#define SIO1TXB (volatile int *)0xa0efd11c -#define SIO1RXB (volatile int *)0xa0efd120 -/********************************* - -M32102 PORT - -*********************************/ -#define PIEN (UB *)0xa0EF1003 /* input enable */ - -#define P0DATA (UB *)0xa0EF1020 /* data */ -#define P1DATA (UB *)0xa0EF1021 -#define P2DATA (UB *)0xa0EF1022 -#define P3DATA (UB *)0xa0EF1023 -#define P4DATA (UB *)0xa0EF1024 -#define P5DATA (UB *)0xa0EF1025 -#define P6DATA (UB *)0xa0EF1026 -#define P7DATA (UB *)0xa0EF1027 - -#define P0DIR (UB *)0xa0EF1040 /* direction */ -#define P1DIR (UB *)0xa0EF1041 -#define P2DIR (UB *)0xa0EF1042 -#define P3DIR (UB *)0xa0EF1043 -#define P4DIR (UB *)0xa0EF1044 -#define P5DIR (UB *)0xa0EF1045 -#define P6DIR (UB *)0xa0EF1046 -#define P7DIR (UB *)0xa0EF1047 - -#define P0MOD (US *)0xa0EF1060 /* mode control */ -#define P1MOD (US *)0xa0EF1062 -#define P2MOD (US *)0xa0EF1064 -#define P3MOD (US *)0xa0EF1066 -#define P4MOD (US *)0xa0EF1068 -#define P5MOD (US *)0xa0EF106A -#define P6MOD (US *)0xa0EF106C -#define P7MOD (US *)0xa0EF106E - -#define P0ODCR (UB *)0xa0EF1080 /* open-drain control */ -#define P1ODCR (UB *)0xa0EF1081 -#define P2ODCR (UB *)0xa0EF1082 -#define P3ODCR (UB *)0xa0EF1083 -#define P4ODCR (UB *)0xa0EF1084 -#define P5ODCR (UB *)0xa0EF1085 -#define P6ODCR (UB *)0xa0EF1086 -#define P7ODCR (UB *)0xa0EF1087 - -/********************************* - -M32102 Cache - -********************************/ - -#define MCCR (US *)0xFFFFFFFE - - -#else /* __ASSEMBLY__ */ - -;; -;; PIO 0x80ef1000 -;; - -#define PIEN 0xa0ef1000 - -#define P0DATA 0xa0ef1020 -#define P1DATA 0xa0ef1021 -#define P2DATA 0xa0ef1022 -#define P3DATA 0xa0ef1023 -#define P4DATA 0xa0ef1024 -#define P5DATA 0xa0ef1025 -#define P6DATA 0xa0ef1026 -#define P7DATA 0xa0ef1027 - -#define P0DIR 0xa0ef1040 -#define P1DIR 0xa0ef1041 -#define P2DIR 0xa0ef1042 -#define P3DIR 0xa0ef1043 -#define P4DIR 0xa0ef1044 -#define P5DIR 0xa0ef1045 -#define P6DIR 0xa0ef1046 -#define P7DIR 0xa0ef1047 - -#define P0MOD 0xa0ef1060 -#define P1MOD 0xa0ef1062 -#define P2MOD 0xa0ef1064 -#define P3MOD 0xa0ef1066 -#define P4MOD 0xa0ef1068 -#define P5MOD 0xa0ef106a -#define P6MOD 0xa0ef106c -#define P7MOD 0xa0ef106e -; -#define P0ODCR 0xa0ef1080 -#define P1ODCR 0xa0ef1081 -#define P2ODCR 0xa0ef1082 -#define P3ODCR 0xa0ef1083 -#define P4ODCR 0xa0ef1084 -#define P5ODCR 0xa0ef1085 -#define P6ODCR 0xa0ef1086 -#define P7ODCR 0xa0ef1087 - -;; -;; WDT 0xa0ef2000 -;; - -#define WDTCR 0xa0ef2000 - - -;; -;; CLK 0xa0ef4000 -;; - -#define CPUCLKCR 0xa0ef4000 -#define CLKMOD 0xa0ef4004 -#define PLLCR 0xa0ef4008 - - -;; -;; BSEL 0xa0ef5000 -;; - -#define BSEL0CR 0xa0ef5000 -#define BSEL1CR 0xa0ef5004 -#define BSEL2CR 0xa0ef5008 -#define BSEL3CR 0xa0ef500c -#define BSEL4CR 0xa0ef5010 -#define BSEL5CR 0xa0ef5014 - - -;; -;; SDRAMC 0xa0ef6000 -;; - -#define SDRF0 0xa0ef6000 -#define SDRF1 0xa0ef6004 -#define SDIR0 0xa0ef6008 -#define SDIR1 0xa0ef600c -#define SDBR 0xa0ef6010 - -;; CH0 -#define SD0ADR 0xa0ef6020 -#define SD0SZ 0xa0ef6022 -#define SD0ER 0xa0ef6024 -#define SD0TR 0xa0ef6028 -#define SD0MOD 0xa0ef602c - -;; CH1 -#define SD1ADR 0xa0ef6040 -#define SD1SZ 0xa0ef6042 -#define SD1ER 0xa0ef6044 -#define SD1TR 0xa0ef6048 -#define SD1MOD 0xa0ef604c - - -;; -;; DMAC 0xa0ef8000 -;; - -#define DMAEN 0xa0ef8000 -#define DMAISTS 0xa0ef8004 -#define DMAEDET 0xa0ef8008 -#define DMAASTS 0xa0ef800c - -;; CH0 -#define DMA0CR0 0xa0ef8100 -#define DMA0CR1 0xa0ef8104 -#define DMA0CSA 0xa0ef8108 -#define DMA0RSA 0xa0ef810c -#define DMA0CDA 0xa0ef8110 -#define DMA0RDA 0xa0ef8114 -#define DMA0CBCUT 0xa0ef8118 -#define DMA0RBCUT 0xa0ef811c - -;; CH1 -#define DMA1CR0 0xa0ef8200 -#define DMA1CR1 0xa0ef8204 -#define DMA1CSA 0xa0ef8208 -#define DMA1RSA 0xa0ef820c -#define DMA1CDA 0xa0ef8210 -#define DMA1RDA 0xa0ef8214 -#define DMA1CBCUT 0xa0ef8218 -#define DMA1RBCUT 0xa0ef821c - - -;; -;; MFT 0xa0efc000 -;; - -#define MFTCR 0xa0efc000 -#define MFTRPR 0xa0efc004 - -;; CH0 -#define MFT0MOD 0xa0efc100 -#define MFT0BOS 0xa0efc104 -#define MFT0CUT 0xa0efc108 -#define MFT0RLD 0xa0efc10c -#define MFT0CMPRLD 0xa0efc110 - -;; CH1 -#define MFT1MOD 0xa0efc200 -#define MFT1BOS 0xa0efc204 -#define MFT1CUT 0xa0efc208 -#define MFT1RLD 0xa0efc20c -#define MFT1CMPRLD 0xa0efc210 - -;; CH2 -#define MFT2MOD 0xa0efc300 -#define MFT2BOS 0xa0efc304 -#define MFT2CUT 0xa0efc308 -#define MFT2RLD 0xa0efc30c -#define MFT2CMPRLD 0xa0efc310 - -;; CH3 -#define MFT3MOD 0xa0efc400 -#define MFT3BOS 0xa0efc404 -#define MFT3CUT 0xa0efc408 -#define MFT3RLD 0xa0efc40c -#define MFT3CMPRLD 0xa0efc410 - -;; CH4 -#define MFT4MOD 0xa0efc500 -#define MFT4BOS 0xa0efc504 -#define MFT4CUT 0xa0efc508 -#define MFT4RLD 0xa0efc50c -#define MFT4CMPRLD 0xa0efc510 - -;; CH5 -#define MFT5MOD 0xa0efc600 -#define MFT5BOS 0xa0efc604 -#define MFT5CUT 0xa0efc608 -#define MFT5RLD 0xa0efc60c -#define MFT5CMPRLD 0xa0efc610 - - -;; -;; SIO 0xa0efd000 -;; - -;; CH0 -#define SIO0CR 0xa0efd000 -#define SIO0MOD0 0xa0efd004 -#define SIO0MOD1 0xa0efd008 -#define SIO0STS 0xa0efd00c -#define SIO0IMASK 0xa0efd010 -#define SIO0BAUR 0xa0efd014 -#define SIO0RBAUR 0xa0efd018 -#define SIO0TXB 0xa0efd01c -#define SIO0RXB 0xa0efd020 - -;; CH1 -#define SIO1CR 0xa0efd100 -#define SIO1MOD0 0xa0efd104 -#define SIO1MOD1 0xa0efd108 -#define SIO1STS 0xa0efd10c -#define SIO1IMASK 0xa0efd110 -#define SIO1BAUR 0xa0efd114 -#define SIO1RBAUR 0xa0efd118 -#define SIO1TXB 0xa0efd11c -#define SIO1RXB 0xa0efd120 - -;; CH2 -#define SIO2CR 0xa0efd200 -#define SIO2MOD0 0xa0efd204 -#define SIO2MOD1 0xa0efd208 -#define SIO2STS 0xa0efd20c -#define SIO2IMASK 0xa0efd210 -#define SIO2BAUR 0xa0efd214 -#define SIO2RBAUR 0xa0efd218 -#define SIO2TXB 0xa0efd21c -#define SIO2RXB 0xa0efd220 - -;; CH3 -#define SIO3CR 0xa0efd300 -#define SIO3MOD0 0xa0efd304 -#define SIO3MOD1 0xa0efd308 -#define SIO3STS 0xa0efd30c -#define SIO3IMASK 0xa0efd310 -#define SIO3BAUR 0xa0efd314 -#define SIO3RBAUR 0xa0efd318 -#define SIO3TXB 0xa0efd31c -#define SIO3RXB 0xa0efd320 - -;; CH4 -#define SIO4CR 0xa0efd400 -#define SIO4MOD0 0xa0efd404 -#define SIO4MOD1 0xa0efd408 -#define SIO4STS 0xa0efd40c -#define SIO4IMASK 0xa0efd410 -#define SIO4BAUR 0xa0efd414 -#define SIO4RBAUR 0xa0efd418 -#define SIO4TXB 0xa0efd41c -#define SIO4RXB 0xa0efd420 - - -;; -;; ICU 0xa0eff000 -;; - -#define ICUISTS 0xa0eff004 -#define ICUIREQ0 0xa0eff008 -#define ICUIREQ1 0xa0eff00c - -#define ICUSBICR 0xa0eff018 -#define ICUIMASK 0xa0eff01c - -#define ICUCR1 0xa0eff200 -#define ICUCR2 0xa0eff204 -#define ICUCR3 0xa0eff208 -#define ICUCR4 0xa0eff20c -#define ICUCR5 0xa0eff210 -#define ICUCR6 0xa0eff214 -#define ICUCR7 0xa0eff218 - -#define ICUCR16 0xa0eff23c -#define ICUCR17 0xa0eff240 -#define ICUCR18 0xa0eff244 -#define ICUCR19 0xa0eff248 -#define ICUCR20 0xa0eff24c -#define ICUCR21 0xa0eff250 - -#define ICUCR32 0xa0eff27c -#define ICUCR33 0xa0eff280 - -#define ICUCR48 0xa0eff2bc -#define ICUCR49 0xa0eff2c0 -#define ICUCR50 0xa0eff2c4 -#define ICUCR51 0xa0eff2c8 -#define ICUCR52 0xa0eff2cc -#define ICUCR53 0xa0eff2d0 -#define ICUCR54 0xa0eff2d4 -#define ICUCR55 0xa0eff2d8 -#define ICUCR56 0xa0eff2dc -#define ICUCR57 0xa0eff2e0 - -;; -;; CACHE -;; - -#define MCCR 0xfffffffc - - -#endif /* __ASSEMBLY__ */ diff --git a/include/asm-m32r/m32r.h b/include/asm-m32r/m32r.h index fd2b282..ec142be 100644 --- a/include/asm-m32r/m32r.h +++ b/include/asm-m32r/m32r.h @@ -16,7 +16,6 @@ || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \ || defined(CONFIG_CHIP_OPSP) #include -#include #endif /* Platform type */ -- cgit v0.10.2 From 960c2a89a051333d2e6793a416d9a33c4b116b41 Mon Sep 17 00:00:00 2001 From: Hirokazu Takata Date: Tue, 21 Jun 2005 17:16:16 -0700 Subject: [PATCH] m32r: Update defconfig files Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/m32r/defconfig b/arch/m32r/defconfig index 417c95b..8530930 100644 --- a/arch/m32r/defconfig +++ b/arch/m32r/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc4 -# Wed Feb 16 21:10:44 2005 +# Linux kernel version: 2.6.12-rc5 +# Fri Jun 3 16:20:11 2005 # CONFIG_M32R=y # CONFIG_UID16 is not set @@ -16,6 +16,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -28,13 +29,15 @@ CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=14 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set CONFIG_EMBEDDED=y # CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -44,6 +47,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -65,6 +69,7 @@ CONFIG_PLAT_M32700UT=y # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set +# CONFIG_PLAT_MAPPI3 is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set # CONFIG_CHIP_VDEC2 is not set @@ -268,7 +273,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -393,18 +397,6 @@ CONFIG_INPUT=y # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_LIBPS2 is not set -# CONFIG_SERIO_RAW is not set - -# # Input Device Drivers # # CONFIG_INPUT_KEYBOARD is not set @@ -414,6 +406,17 @@ CONFIG_SERIO_SERPORT=y # CONFIG_INPUT_MISC is not set # +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# # Character devices # CONFIG_VT=y @@ -465,6 +468,10 @@ CONFIG_DS1302=y # CONFIG_RAW_DRIVER is not set # +# TPM devices +# + +# # I2C support # # CONFIG_I2C is not set @@ -508,8 +515,14 @@ CONFIG_VIDEO_M32R_AR_M64278=y # Graphics support # CONFIG_FB=y +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_SOFT_CURSOR is not set +# CONFIG_FB_MACMODES is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # @@ -543,10 +556,6 @@ CONFIG_LOGO_LINUX_CLUT224=y # CONFIG_USB_ARCH_HAS_OHCI is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# - -# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -719,8 +728,9 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_DEBUG_PREEMPT=y +CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_FRAME_POINTER is not set diff --git a/arch/m32r/m32700ut/defconfig.m32700ut.smp b/arch/m32r/m32700ut/defconfig.m32700ut.smp index 1c00218..3e607d9 100644 --- a/arch/m32r/m32700ut/defconfig.m32700ut.smp +++ b/arch/m32r/m32700ut/defconfig.m32700ut.smp @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc4 -# Wed Feb 16 21:10:50 2005 +# Linux kernel version: 2.6.12-rc5 +# Fri Jun 3 16:20:58 2005 # CONFIG_M32R=y # CONFIG_UID16 is not set @@ -15,6 +15,7 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -27,13 +28,16 @@ CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=15 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set +# CONFIG_CPUSETS is not set CONFIG_EMBEDDED=y # CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -43,6 +47,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -65,6 +70,7 @@ CONFIG_PLAT_M32700UT=y # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set +# CONFIG_PLAT_MAPPI3 is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set # CONFIG_CHIP_VDEC2 is not set @@ -271,7 +277,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -396,18 +401,6 @@ CONFIG_INPUT=y # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_LIBPS2 is not set -# CONFIG_SERIO_RAW is not set - -# # Input Device Drivers # # CONFIG_INPUT_KEYBOARD is not set @@ -417,6 +410,17 @@ CONFIG_SERIO_SERPORT=y # CONFIG_INPUT_MISC is not set # +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# # Character devices # CONFIG_VT=y @@ -468,6 +472,10 @@ CONFIG_DS1302=y # CONFIG_RAW_DRIVER is not set # +# TPM devices +# + +# # I2C support # # CONFIG_I2C is not set @@ -511,8 +519,14 @@ CONFIG_VIDEO_M32R_AR_M64278=y # Graphics support # CONFIG_FB=y +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_SOFT_CURSOR is not set +# CONFIG_FB_MACMODES is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # @@ -546,10 +560,6 @@ CONFIG_LOGO_LINUX_CLUT224=y # CONFIG_USB_ARCH_HAS_OHCI is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# - -# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -722,8 +732,9 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_DEBUG_PREEMPT=y +CONFIG_LOG_BUF_SHIFT=15 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_FRAME_POINTER is not set diff --git a/arch/m32r/m32700ut/defconfig.m32700ut.up b/arch/m32r/m32700ut/defconfig.m32700ut.up index 805357f..2d3e7cd 100644 --- a/arch/m32r/m32700ut/defconfig.m32700ut.up +++ b/arch/m32r/m32700ut/defconfig.m32700ut.up @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc4 -# Wed Feb 16 21:10:54 2005 +# Linux kernel version: 2.6.12-rc5 +# Fri Jun 3 16:21:34 2005 # CONFIG_M32R=y # CONFIG_UID16 is not set @@ -16,6 +16,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -28,13 +29,15 @@ CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=14 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set CONFIG_EMBEDDED=y # CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -44,6 +47,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -65,6 +69,7 @@ CONFIG_PLAT_M32700UT=y # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set +# CONFIG_PLAT_MAPPI3 is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set # CONFIG_CHIP_VDEC2 is not set @@ -268,7 +273,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -393,18 +397,6 @@ CONFIG_INPUT=y # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_LIBPS2 is not set -# CONFIG_SERIO_RAW is not set - -# # Input Device Drivers # # CONFIG_INPUT_KEYBOARD is not set @@ -414,6 +406,17 @@ CONFIG_SERIO_SERPORT=y # CONFIG_INPUT_MISC is not set # +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# # Character devices # CONFIG_VT=y @@ -465,6 +468,10 @@ CONFIG_DS1302=y # CONFIG_RAW_DRIVER is not set # +# TPM devices +# + +# # I2C support # # CONFIG_I2C is not set @@ -508,8 +515,14 @@ CONFIG_VIDEO_M32R_AR_M64278=y # Graphics support # CONFIG_FB=y +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_SOFT_CURSOR is not set +# CONFIG_FB_MACMODES is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # @@ -543,10 +556,6 @@ CONFIG_LOGO_LINUX_CLUT224=y # CONFIG_USB_ARCH_HAS_OHCI is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# - -# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -719,8 +728,9 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_DEBUG_PREEMPT=y +CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_FRAME_POINTER is not set diff --git a/arch/m32r/mappi/defconfig.nommu b/arch/m32r/mappi/defconfig.nommu index 714aa6e..a8425fb 100644 --- a/arch/m32r/mappi/defconfig.nommu +++ b/arch/m32r/mappi/defconfig.nommu @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc4 -# Wed Feb 16 21:10:57 2005 +# Linux kernel version: 2.6.12-rc5 +# Fri Jun 3 16:21:46 2005 # CONFIG_M32R=y # CONFIG_UID16 is not set @@ -16,6 +16,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -26,13 +27,15 @@ CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=14 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set CONFIG_EMBEDDED=y # CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -41,6 +44,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -62,6 +66,7 @@ CONFIG_PLAT_MAPPI=y # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set +# CONFIG_PLAT_MAPPI3 is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set # CONFIG_CHIP_VDEC2 is not set @@ -202,7 +207,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -325,18 +329,6 @@ CONFIG_INPUT=y # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_LIBPS2 is not set -# CONFIG_SERIO_RAW is not set - -# # Input Device Drivers # # CONFIG_INPUT_KEYBOARD is not set @@ -346,6 +338,17 @@ CONFIG_SERIO_SERPORT=y # CONFIG_INPUT_MISC is not set # +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# # Character devices # # CONFIG_VT is not set @@ -394,6 +397,10 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_RAW_DRIVER is not set # +# TPM devices +# + +# # I2C support # # CONFIG_I2C is not set @@ -434,10 +441,6 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_USB_ARCH_HAS_OHCI is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# - -# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -595,8 +598,9 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_DEBUG_PREEMPT=y +CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_FRAME_POINTER is not set diff --git a/arch/m32r/mappi/defconfig.smp b/arch/m32r/mappi/defconfig.smp index 956a8e2..1a7f3cd 100644 --- a/arch/m32r/mappi/defconfig.smp +++ b/arch/m32r/mappi/defconfig.smp @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc4 -# Wed Feb 16 21:11:02 2005 +# Linux kernel version: 2.6.12-rc5 +# Fri Jun 3 16:21:52 2005 # CONFIG_M32R=y # CONFIG_UID16 is not set @@ -17,6 +17,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -28,13 +29,16 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=15 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +# CONFIG_CPUSETS is not set CONFIG_EMBEDDED=y # CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -44,6 +48,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -66,6 +71,7 @@ CONFIG_PLAT_MAPPI=y # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set +# CONFIG_PLAT_MAPPI3 is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set # CONFIG_CHIP_VDEC2 is not set @@ -139,8 +145,8 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set -CONFIG_MTD_PARTITIONS=y # CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y CONFIG_MTD_REDBOOT_PARTS=y CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 # CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set @@ -294,7 +300,6 @@ CONFIG_NET=y # Networking options # # CONFIG_PACKET is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -420,18 +425,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_SERIO_SERPORT is not set -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_LIBPS2 is not set -# CONFIG_SERIO_RAW is not set - -# # Input Device Drivers # # CONFIG_INPUT_KEYBOARD is not set @@ -441,6 +434,17 @@ CONFIG_SERIO=y # CONFIG_INPUT_MISC is not set # +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# # Character devices # # CONFIG_VT is not set @@ -489,6 +493,10 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_RAW_DRIVER is not set # +# TPM devices +# + +# # I2C support # # CONFIG_I2C is not set @@ -529,10 +537,6 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_USB_ARCH_HAS_OHCI is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# - -# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -708,8 +712,9 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_DEBUG_PREEMPT=y +CONFIG_LOG_BUF_SHIFT=15 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_FRAME_POINTER is not set diff --git a/arch/m32r/mappi/defconfig.up b/arch/m32r/mappi/defconfig.up index c9253e9..38910fb 100644 --- a/arch/m32r/mappi/defconfig.up +++ b/arch/m32r/mappi/defconfig.up @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc4 -# Wed Feb 16 21:11:07 2005 +# Linux kernel version: 2.6.12-rc5 +# Fri Jun 3 16:21:59 2005 # CONFIG_M32R=y # CONFIG_UID16 is not set @@ -17,6 +17,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -28,13 +29,15 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=14 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_EMBEDDED=y # CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -44,6 +47,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -65,6 +69,7 @@ CONFIG_PLAT_MAPPI=y # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set +# CONFIG_PLAT_MAPPI3 is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set # CONFIG_CHIP_VDEC2 is not set @@ -135,8 +140,8 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set -CONFIG_MTD_PARTITIONS=y # CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y CONFIG_MTD_REDBOOT_PARTS=y CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 # CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set @@ -290,7 +295,6 @@ CONFIG_NET=y # Networking options # # CONFIG_PACKET is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -416,18 +420,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_SERIO_SERPORT is not set -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_LIBPS2 is not set -# CONFIG_SERIO_RAW is not set - -# # Input Device Drivers # # CONFIG_INPUT_KEYBOARD is not set @@ -437,6 +429,17 @@ CONFIG_SERIO=y # CONFIG_INPUT_MISC is not set # +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# # Character devices # # CONFIG_VT is not set @@ -485,6 +488,10 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_RAW_DRIVER is not set # +# TPM devices +# + +# # I2C support # # CONFIG_I2C is not set @@ -525,10 +532,6 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_USB_ARCH_HAS_OHCI is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# - -# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -704,8 +707,9 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_DEBUG_PREEMPT=y +CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_FRAME_POINTER is not set diff --git a/arch/m32r/mappi2/defconfig.vdec2 b/arch/m32r/mappi2/defconfig.vdec2 index c14791d..56f287b 100644 --- a/arch/m32r/mappi2/defconfig.vdec2 +++ b/arch/m32r/mappi2/defconfig.vdec2 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc4 -# Wed Feb 16 21:11:10 2005 +# Linux kernel version: 2.6.12-rc5 +# Fri Jun 3 16:22:02 2005 # CONFIG_M32R=y # CONFIG_UID16 is not set @@ -16,6 +16,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -28,13 +29,15 @@ CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=14 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set CONFIG_EMBEDDED=y # CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -44,6 +47,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -65,6 +69,7 @@ CONFIG_KMOD=y # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set CONFIG_PLAT_MAPPI2=y +# CONFIG_PLAT_MAPPI3 is not set # CONFIG_CHIP_M32700 is not set # CONFIG_CHIP_M32102 is not set CONFIG_CHIP_VDEC2=y @@ -264,7 +269,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -389,18 +393,6 @@ CONFIG_INPUT=y # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_LIBPS2 is not set -# CONFIG_SERIO_RAW is not set - -# # Input Device Drivers # # CONFIG_INPUT_KEYBOARD is not set @@ -410,6 +402,17 @@ CONFIG_SERIO_SERPORT=y # CONFIG_INPUT_MISC is not set # +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# # Character devices # CONFIG_VT=y @@ -460,6 +463,10 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_RAW_DRIVER is not set # +# TPM devices +# + +# # I2C support # # CONFIG_I2C is not set @@ -521,10 +528,6 @@ CONFIG_DUMMY_CONSOLE=y # CONFIG_USB_ARCH_HAS_OHCI is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# - -# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -697,8 +700,9 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_DEBUG_PREEMPT=y +CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_FRAME_POINTER is not set diff --git a/arch/m32r/oaks32r/defconfig.nommu b/arch/m32r/oaks32r/defconfig.nommu index f2da9be..3f9fe51 100644 --- a/arch/m32r/oaks32r/defconfig.nommu +++ b/arch/m32r/oaks32r/defconfig.nommu @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc4 -# Wed Feb 16 21:11:13 2005 +# Linux kernel version: 2.6.12-rc5 +# Fri Jun 3 16:22:04 2005 # CONFIG_M32R=y # CONFIG_UID16 is not set @@ -16,6 +16,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -26,12 +27,14 @@ CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=14 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set CONFIG_EMBEDDED=y # CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -40,6 +43,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -61,6 +65,7 @@ CONFIG_KMOD=y # CONFIG_PLAT_OPSPUT is not set CONFIG_PLAT_OAKS32R=y # CONFIG_PLAT_MAPPI2 is not set +# CONFIG_PLAT_MAPPI3 is not set # CONFIG_CHIP_M32700 is not set CONFIG_CHIP_M32102=y # CONFIG_CHIP_VDEC2 is not set @@ -92,10 +97,6 @@ CONFIG_PREEMPT=y # CONFIG_PCCARD is not set # -# PC-card bridges -# - -# # PCI Hotplug Support # @@ -193,7 +194,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -311,18 +311,6 @@ CONFIG_INPUT=y # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_LIBPS2 is not set -# CONFIG_SERIO_RAW is not set - -# # Input Device Drivers # # CONFIG_INPUT_KEYBOARD is not set @@ -332,6 +320,17 @@ CONFIG_SERIO_SERPORT=y # CONFIG_INPUT_MISC is not set # +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# # Character devices # # CONFIG_VT is not set @@ -375,6 +374,10 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_RAW_DRIVER is not set # +# TPM devices +# + +# # I2C support # # CONFIG_I2C is not set @@ -415,10 +418,6 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_USB_ARCH_HAS_OHCI is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# - -# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -574,8 +573,9 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_DEBUG_PREEMPT=y +CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_FRAME_POINTER is not set diff --git a/arch/m32r/opsput/defconfig.opsput b/arch/m32r/opsput/defconfig.opsput index a87e1ea..66adec6 100644 --- a/arch/m32r/opsput/defconfig.opsput +++ b/arch/m32r/opsput/defconfig.opsput @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc4 -# Wed Feb 16 21:11:41 2005 +# Linux kernel version: 2.6.12-rc5 +# Fri Jun 3 16:22:06 2005 # CONFIG_M32R=y # CONFIG_UID16 is not set @@ -15,6 +15,7 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -27,13 +28,15 @@ CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=14 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set CONFIG_EMBEDDED=y # CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -43,6 +46,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -64,6 +68,7 @@ CONFIG_KMOD=y CONFIG_PLAT_OPSPUT=y # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set +# CONFIG_PLAT_MAPPI3 is not set # CONFIG_CHIP_M32700 is not set # CONFIG_CHIP_M32102 is not set # CONFIG_CHIP_VDEC2 is not set @@ -243,7 +248,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -368,18 +372,6 @@ CONFIG_INPUT=y # CONFIG_INPUT_EVBUG is not set # -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_LIBPS2 is not set -# CONFIG_SERIO_RAW is not set - -# # Input Device Drivers # # CONFIG_INPUT_KEYBOARD is not set @@ -389,6 +381,17 @@ CONFIG_SERIO_SERPORT=y # CONFIG_INPUT_MISC is not set # +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# # Character devices # # CONFIG_VT is not set @@ -438,6 +441,10 @@ CONFIG_DS1302=y # CONFIG_RAW_DRIVER is not set # +# TPM devices +# + +# # I2C support # # CONFIG_I2C is not set @@ -478,10 +485,6 @@ CONFIG_DS1302=y # CONFIG_USB_ARCH_HAS_OHCI is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# - -# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -654,8 +657,10 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y # CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set -- cgit v0.10.2 From 5757b284a300e0e5d2173750906625b6470bd9f0 Mon Sep 17 00:00:00 2001 From: Hirokazu Takata Date: Tue, 21 Jun 2005 17:16:17 -0700 Subject: [PATCH] m32r: Use asm-generic/div64.h The current include/asm-m32r/div64.h of 2.6.12-rc5 looks buggy. Here is a patch for updating it to use asm-generic/div64.h for m32r like other architectures. Signed-off-by: Hitoshi Yamamoto Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-m32r/div64.h b/include/asm-m32r/div64.h index 417a51b..6cd978c 100644 --- a/include/asm-m32r/div64.h +++ b/include/asm-m32r/div64.h @@ -1,38 +1 @@ -#ifndef _ASM_M32R_DIV64 -#define _ASM_M32R_DIV64 - -/* $Id$ */ - -/* unsigned long long division. - * Input: - * unsigned long long n - * unsigned long base - * Output: - * n = n / base; - * return value = n % base; - */ -#define do_div(n, base) \ -({ \ - unsigned long _res, _high, _mid, _low; \ - \ - _low = (n) & 0xffffffffUL; \ - _high = (n) >> 32; \ - if (_high) { \ - _mid = (_high % (unsigned long)(base)) << 16; \ - _high = _high / (unsigned long)(base); \ - _mid += _low >> 16; \ - _low &= 0x0000ffffUL; \ - _low += (_mid % (unsigned long)(base)) << 16; \ - _mid = _mid / (unsigned long)(base); \ - _res = _low % (unsigned long)(base); \ - _low = _low / (unsigned long)(base); \ - n = _low + ((long long)_mid << 16) + \ - ((long long)_high << 32); \ - } else { \ - _res = _low % (unsigned long)(base); \ - n = (_low / (unsigned long)(base)); \ - } \ - _res; \ -}) - -#endif /* _ASM_M32R_DIV64 */ +#include -- cgit v0.10.2 From dbce706e2550253c5ab6043f4f5dfde0cd02470f Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Tue, 21 Jun 2005 17:16:19 -0700 Subject: [PATCH] uml: add and use generic hw_controller_type->release With Chris Wedgwood Currently UML must explicitly call the UML-specific free_irq_by_irq_and_dev() for each free_irq call it's done. This is needed because ->shutdown and/or ->disable are only called when the last "action" for that irq is removed. Instead, for UML shared IRQs (UML IRQs are very often, if not always, shared), for each dev_id some setup is done, which must be cleared on the release of that fd. For instance, for each open console a new instance (i.e. new dev_id) of the same IRQ is requested(). Exactly, a fd is stored in an array (pollfds), which is after read by a host thread and passed to poll(). Each event registered by poll() triggers an interrupt. So, for each free_irq() we must remove the corresponding host fd from the table, which we do via this -release() method. In this patch we add an appropriate hook for this, and remove all uses of it by pointing the hook to the said procedure; this is safe to do since the said procedure. Also some cosmetic improvements are included. This is heavily based on some work by Chris Wedgwood, which however didn't get the patch merged for something I'd call a "misunderstanding" (the need for this patch wasn't cleanly explained, thus adding the generic hook was felt as undesirable). Signed-off-by: Paolo 'Blaisorblade' Giarrusso CC: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 025d3be..562f864 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -406,14 +406,12 @@ void line_disable(struct tty_struct *tty, int current_irq) if(line->driver->read_irq == current_irq) free_irq_later(line->driver->read_irq, tty); else { - free_irq_by_irq_and_dev(line->driver->read_irq, tty); free_irq(line->driver->read_irq, tty); } if(line->driver->write_irq == current_irq) free_irq_later(line->driver->write_irq, tty); else { - free_irq_by_irq_and_dev(line->driver->write_irq, tty); free_irq(line->driver->write_irq, tty); } diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 4eeaf88..5388a74 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -146,7 +146,6 @@ static int uml_net_close(struct net_device *dev) netif_stop_queue(dev); spin_lock(&lp->lock); - free_irq_by_irq_and_dev(dev->irq, dev); free_irq(dev->irq, dev); if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index b5ee074..c41efd2 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -257,7 +257,6 @@ int port_wait(void *data) * connection. Then we loop here throwing out failed * connections until a good one is found. */ - free_irq_by_irq_and_dev(TELNETD_IRQ, conn); free_irq(TELNETD_IRQ, conn); if(conn->fd >= 0) break; diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c index a4fdf35..d269a80 100644 --- a/arch/um/drivers/xterm_kern.c +++ b/arch/um/drivers/xterm_kern.c @@ -69,7 +69,6 @@ int xterm_fd(int socket, int *pid_out) * isn't set) this will hang... */ wait_for_completion(&data->ready); - free_irq_by_irq_and_dev(XTERM_IRQ, data); free_irq(XTERM_IRQ, data); ret = data->new_fd; diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index d44fb52..9f18061 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -124,14 +124,16 @@ void irq_unlock(unsigned long flags) spin_unlock_irqrestore(&irq_spinlock, flags); } -/* presently hw_interrupt_type must define (startup || enable) && - * disable && end */ +/* hw_interrupt_type must define (startup || enable) && + * (shutdown || disable) && end */ static void dummy(unsigned int irq) { } -static struct hw_interrupt_type SIGIO_irq_type = { +/* This is used for everything else than the timer. */ +static struct hw_interrupt_type normal_irq_type = { .typename = "SIGIO", + .release = free_irq_by_irq_and_dev, .disable = dummy, .enable = dummy, .ack = dummy, @@ -140,6 +142,7 @@ static struct hw_interrupt_type SIGIO_irq_type = { static struct hw_interrupt_type SIGVTALRM_irq_type = { .typename = "SIGVTALRM", + .release = free_irq_by_irq_and_dev, .shutdown = dummy, /* never called */ .disable = dummy, .enable = dummy, @@ -160,7 +163,7 @@ void __init init_IRQ(void) irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = NULL; irq_desc[i].depth = 1; - irq_desc[i].handler = &SIGIO_irq_type; + irq_desc[i].handler = &normal_irq_type; enable_irq(i); } } diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index b3074cb..c3ccaf2 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c @@ -85,8 +85,6 @@ void sigio_handler(int sig, union uml_pt_regs *regs) next = irq_fd->next; if(irq_fd->freed){ free_irq(irq_fd->irq, irq_fd->id); - free_irq_by_irq_and_dev(irq_fd->irq, - irq_fd->id); } } } diff --git a/include/linux/irq.h b/include/linux/irq.h index c3ff4d1..b68ad80 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -47,6 +47,7 @@ struct hw_interrupt_type { void (*ack)(unsigned int irq); void (*end)(unsigned int irq); void (*set_affinity)(unsigned int irq, cpumask_t dest); + void (*release)(unsigned int irq, void *dev_id); }; typedef struct hw_interrupt_type hw_irq_controller; diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 5202e4c..5fde817 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -255,6 +255,10 @@ void free_irq(unsigned int irq, void *dev_id) /* Found it - now remove it from the list of entries */ *pp = action->next; + + if (desc->handler->release) + desc->handler->release(irq, dev_id); + if (!desc->action) { desc->status |= IRQ_DISABLED; if (desc->handler->shutdown) -- cgit v0.10.2 From faec1e99ba9ca7371d9aee1656938373133c4b21 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Tue, 21 Jun 2005 17:16:21 -0700 Subject: [PATCH] uml: complete hw_controller_type->release conversion This occurrence of free_irq_by_irq_and_dev() was missed when converting UML to the use of hw_controller_type->release. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 562f864..0f59736 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -756,7 +756,6 @@ static void unregister_winch(struct tty_struct *tty) if(winch->pid != -1) os_kill_process(winch->pid, 1); - free_irq_by_irq_and_dev(WINCH_IRQ, winch); free_irq(WINCH_IRQ, winch); list_del(&winch->list); kfree(winch); -- cgit v0.10.2 From b77d6adc922b8bbf8b16b67f567958c42962cf88 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Tue, 21 Jun 2005 17:16:24 -0700 Subject: [PATCH] uml: make hw_controller_type->release exist only for archs needing it With Chris Wedgwood As suggested by Chris, we can make the "just added" method ->release conditional to UML only (better: to archs requesting it, i.e. only UML currently), so that other archs don't get this unneeded crud, and if UML won't need it any more we can kill this. Signed-off-by: Paolo 'Blaisorblade' Giarrusso CC: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/Kconfig b/arch/um/Kconfig index c529218..b8e952c 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -35,6 +35,11 @@ config GENERIC_CALIBRATE_DELAY bool default y +# Used in kernel/irq/manage.c and include/linux/irq.h +config IRQ_RELEASE_METHOD + bool + default y + menu "UML-specific options" config MODE_TT diff --git a/include/linux/irq.h b/include/linux/irq.h index b68ad80..7fc1022 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -47,7 +47,10 @@ struct hw_interrupt_type { void (*ack)(unsigned int irq); void (*end)(unsigned int irq); void (*set_affinity)(unsigned int irq, cpumask_t dest); + /* Currently used only by UML, might disappear one day.*/ +#ifdef CONFIG_IRQ_RELEASE_METHOD void (*release)(unsigned int irq, void *dev_id); +#endif }; typedef struct hw_interrupt_type hw_irq_controller; diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 5fde817..ac67009 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -6,6 +6,7 @@ * This file contains driver APIs to the irq subsystem. */ +#include #include #include #include @@ -256,8 +257,11 @@ void free_irq(unsigned int irq, void *dev_id) /* Found it - now remove it from the list of entries */ *pp = action->next; + /* Currently used only by UML, might disappear one day.*/ +#ifdef CONFIG_IRQ_RELEASE_METHOD if (desc->handler->release) desc->handler->release(irq, dev_id); +#endif if (!desc->action) { desc->status |= IRQ_DISABLED; -- cgit v0.10.2 From 60b2737de1b1ddfdb90f3ba622634eb49d6f3603 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Tue, 21 Jun 2005 17:16:25 -0700 Subject: [PATCH] uml: fix linkage of tt mode against NPTL With Al Viro To make sure switcheroo() can execute when we remap all the executable image, we used a trick to make it use a local copy of errno... this trick does not work with NPTL glibc, only with LinuxThreads, so use another (simpler) one to make it work anyway. Hopefully, a lot improved thanks to merging with the version of Al Viro (which had his part of problems, though, i.e. removing a fix to another bug and not fixing the problem on i386). Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/Makefile b/arch/um/Makefile index f2a0c40..3f07390 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -122,7 +122,7 @@ endif CPPFLAGS_vmlinux.lds = $(shell echo -U$(SUBARCH) \ -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE-y) \ - -DKERNEL_STACK_SIZE=$(STACK_SIZE)) + -DKERNEL_STACK_SIZE=$(STACK_SIZE) -DSUBARCH=$(SUBARCH)) #The wrappers will select whether using "malloc" or the kernel allocator. LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index c3faea2..3fd2554 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -3,10 +3,6 @@ # Licensed under the GPL # -extra-y := unmap_fin.o -targets := unmap.o -clean-files := unmap_tmp.o - obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \ syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \ uaccess.o uaccess_user.o @@ -16,14 +12,3 @@ obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/ USER_OBJS := gdb.o time.o tracer.o include arch/um/scripts/Makefile.rules - -UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS)) -UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS)) - -#XXX: partially copied from arch/um/scripts/Makefile.rules -$(obj)/unmap.o: c_flags = -Wp,-MD,$(depfile) $(UNMAP_CFLAGS) - -$(obj)/unmap_fin.o : $(obj)/unmap.o - $(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a) - $(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo - diff --git a/arch/um/kernel/tt/unmap.c b/arch/um/kernel/tt/unmap.c deleted file mode 100644 index 3f7aecd..0000000 --- a/arch/um/kernel/tt/unmap.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include - -int switcheroo(int fd, int prot, void *from, void *to, int size) -{ - if(munmap(to, size) < 0){ - return(-1); - } - if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){ - return(-1); - } - if(munmap(from, size) < 0){ - return(-1); - } - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index dd53555..61dfd4f 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -14,19 +14,10 @@ SECTIONS /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start * is remapped.*/ __binary_start = .; -#ifdef MODE_TT - .thread_private : { - __start_thread_private = .; - errno = .; - . += 4; - arch/um/kernel/tt/unmap_fin.o (.data) - __end_thread_private = .; - } - . = ALIGN(4096); - .remap : { arch/um/kernel/tt/unmap_fin.o (.text) } - /* We want it only if we are in MODE_TT. In both cases, however, when MODE_TT - * is off the resulting binary segfaults.*/ +#ifdef MODE_TT + .remap_data : { arch/um/sys-SUBARCH/unmap_fin.o (.data .bss) } + .remap : { arch/um/sys-SUBARCH/unmap_fin.o (.text) } . = ALIGN(4096); /* Init code and data */ #endif diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 98346c7..7459d09 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -10,6 +10,12 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS) : c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) \ $(CFLAGS_$(notdir $@)) +# The stubs and unmap.o can't try to call mcount or update basic block data +define unprofile + $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) +endef + + quiet_cmd_make_link = SYMLINK $@ cmd_make_link = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@ diff --git a/arch/um/scripts/Makefile.unmap b/arch/um/scripts/Makefile.unmap new file mode 100644 index 0000000..37a8f97 --- /dev/null +++ b/arch/um/scripts/Makefile.unmap @@ -0,0 +1,22 @@ +clean-files += unmap_tmp.o unmap_fin.o unmap.o + +ifdef CONFIG_MODE_TT + +#Always build unmap_fin.o +extra-y += unmap_fin.o +#Do dependency tracking for unmap.o (it will be always built, but won't get the tracking unless we use this). +targets += unmap.o + +#XXX: partially copied from arch/um/scripts/Makefile.rules +$(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS)) + +quiet_cmd_wrapld = LD $@ +define cmd_wrapld + $(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a); \ + $(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo +endef + +$(obj)/unmap_fin.o : $(obj)/unmap.o FORCE + $(call if_changed,wrapld) + +endif diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 4351e56..095bcdb 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -17,3 +17,5 @@ highmem.c-dir = mm module.c-dir = kernel subdir- := util + +include arch/um/scripts/Makefile.unmap diff --git a/arch/um/sys-i386/unmap.c b/arch/um/sys-i386/unmap.c new file mode 100644 index 0000000..1368752 --- /dev/null +++ b/arch/um/sys-i386/unmap.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include + +static int errno; + +static inline _syscall2(int,munmap,void *,start,size_t,len) +static inline _syscall6(void *,mmap2,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset) +int switcheroo(int fd, int prot, void *from, void *to, int size) +{ + if(munmap(to, size) < 0){ + return(-1); + } + if(mmap2(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){ + return(-1); + } + if(munmap(from, size) < 0){ + return(-1); + } + return(0); +} diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 608466a..2bc6f68 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -29,3 +29,5 @@ thunk.S-dir = lib module.c-dir = kernel subdir- := util + +include arch/um/scripts/Makefile.unmap diff --git a/arch/um/sys-x86_64/unmap.c b/arch/um/sys-x86_64/unmap.c new file mode 100644 index 0000000..bc7094c --- /dev/null +++ b/arch/um/sys-x86_64/unmap.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include + +static int errno; + +static inline _syscall2(int,munmap,void *,start,size_t,len) +static inline _syscall6(void *,mmap,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset) +int switcheroo(int fd, int prot, void *from, void *to, int size) +{ + if(munmap(to, size) < 0){ + return(-1); + } + if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){ + return(-1); + } + if(munmap(from, size) < 0){ + return(-1); + } + return(0); +} -- cgit v0.10.2 From 5bdfcfcc0780f58b927a164dfd54d1e1b6767347 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 21 Jun 2005 17:16:26 -0700 Subject: [PATCH] s390: cio max channels checks Fix max channel check in cio_ignore display function. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 4a06c7d..aac83ce 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/blacklist.c * S/390 common I/O routines -- blacklisting of specific devices - * $Revision: 1.33 $ + * $Revision: 1.34 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -289,7 +289,7 @@ static int cio_ignore_read (char *page, char **start, off_t off, len = 0; for (devno = off; /* abuse the page variable * as counter, see fs/proc/generic.c */ - devno <= __MAX_SUBCHANNELS && len + entry_size < count; devno++) { + devno < __MAX_SUBCHANNELS && len + entry_size < count; devno++) { if (!test_bit(devno, bl_dev)) continue; len += sprintf(page + len, "0.0.%04lx", devno); @@ -302,7 +302,7 @@ static int cio_ignore_read (char *page, char **start, off_t off, len += sprintf(page + len, "\n"); } - if (devno <= __MAX_SUBCHANNELS) + if (devno < __MAX_SUBCHANNELS) *eof = 1; *start = (char *) (devno - off); /* number of checked entries */ return len; -- cgit v0.10.2 From 6fd6e4a44ff9ff406bcff69050b508f186507df1 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 21 Jun 2005 17:16:27 -0700 Subject: [PATCH] s390: cio documentation Some clarifications in the cio documentation. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO index a831d9a..59d1166 100644 --- a/Documentation/s390/CommonIO +++ b/Documentation/s390/CommonIO @@ -30,7 +30,7 @@ Command line parameters device numbers (0xabcd or abcd, for 2.4 backward compatibility). You can use the 'all' keyword to ignore all devices. The '!' operator will cause the I/O-layer to _not_ ignore a device. - The order on the command line is not important. + The command line is parsed from left to right. For example, cio_ignore=0.0.0023-0.0.0042,0.0.4711 @@ -72,13 +72,14 @@ Command line parameters /proc/cio_ignore; "add , , ..." will ignore the specified devices. - Note: Already known devices cannot be ignored. + Note: While already known devices can be added to the list of devices to be + ignored, there will be no effect on then. However, if such a device + disappears and then reappeares, it will then be ignored. - For example, if device 0.0.abcd is already known and all other devices - 0.0.a000-0.0.afff are not known, + For example, "echo add 0.0.a000-0.0.accc, 0.0.af00-0.0.afff > /proc/cio_ignore" - will add 0.0.a000-0.0.abcc, 0.0.abce-0.0.accc and 0.0.af00-0.0.afff to the - list of ignored devices and skip 0.0.abcd. + will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored + devices. The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward compatibilty, by the device number in hexadecimal (0xabcd or abcd). @@ -98,7 +99,8 @@ Command line parameters - /proc/s390dbf/cio_trace/hex_ascii Logs the calling of functions in the common I/O-layer and, if applicable, - which subchannel they were called for. + which subchannel they were called for, as well as dumps of some data + structures (like irb in an error case). The level of logging can be changed to be more or less verbose by piping to /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on -- cgit v0.10.2 From 14651c798a2a4d15ccc53d064df28bfd0283bad6 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 21 Jun 2005 17:16:28 -0700 Subject: [PATCH] s390: #ifdefs in compat_ioctls Remove superflous #if .. #endif pairs from compat_ioctl.c. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/kernel/compat_ioctl.c b/arch/s390/kernel/compat_ioctl.c index 03d03c6..24a1e9f 100644 --- a/arch/s390/kernel/compat_ioctl.c +++ b/arch/s390/kernel/compat_ioctl.c @@ -42,7 +42,6 @@ struct ioctl_trans ioctl_start[] = { #include "../../../fs/compat_ioctl.c" /* s390 only ioctls */ -#if defined(CONFIG_DASD) || defined(CONFIG_DASD_MODULE) COMPATIBLE_IOCTL(DASDAPIVER) COMPATIBLE_IOCTL(BIODASDDISABLE) COMPATIBLE_IOCTL(BIODASDENABLE) @@ -59,16 +58,11 @@ COMPATIBLE_IOCTL(BIODASDPRRD) COMPATIBLE_IOCTL(BIODASDPSRD) COMPATIBLE_IOCTL(BIODASDGATTR) COMPATIBLE_IOCTL(BIODASDSATTR) -#if defined(CONFIG_DASD_CMB) || defined(CONFIG_DASD_CMB_MODULE) COMPATIBLE_IOCTL(BIODASDCMFENABLE) COMPATIBLE_IOCTL(BIODASDCMFDISABLE) COMPATIBLE_IOCTL(BIODASDREADALLCMB) -#endif -#endif -#if defined(CONFIG_S390_TAPE) || defined(CONFIG_S390_TAPE_MODULE) COMPATIBLE_IOCTL(TAPE390_DISPLAY) -#endif /* s390 doesn't need handlers here */ COMPATIBLE_IOCTL(TIOCGSERIAL) -- cgit v0.10.2 From 77eb65cbc18d86a9c334964ed4c3d178f5560918 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 21 Jun 2005 17:16:28 -0700 Subject: [PATCH] s390: kernel stack overflow panic die() doesn't return, therefore print registers and then panic instead. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 8b90e95..ca34b6f 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -668,7 +668,10 @@ asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code) asmlinkage void kernel_stack_overflow(struct pt_regs * regs) { - die("Kernel stack overflow", regs, 0); + bust_spinlocks(1); + printk("Kernel stack overflow.\n"); + show_regs(regs); + bust_spinlocks(0); panic("Corrupt kernel stack, can't continue."); } -- cgit v0.10.2 From 447570cfde680d5bf09c47b9c8d1dcf5bcb18f10 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 21 Jun 2005 17:16:29 -0700 Subject: [PATCH] s390: cmm sender parameter visibility Make cmm module parameter "sender" visible in sysfs. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index f5a5bc0..2d5cb13 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -21,7 +21,7 @@ #include static char *sender = "VMRMSVM"; -module_param(sender, charp, 0); +module_param(sender, charp, 0400); MODULE_PARM_DESC(sender, "Guest name that may send SMSG messages (default VMRMSVM)"); -- cgit v0.10.2 From e9b9a04796eade5241452a913ec6f3433437b4f5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 21 Jun 2005 17:16:30 -0700 Subject: [PATCH] s390: memory detection > 32GB The kernel takes a very long time to boot if the memory size is bigger then 32767 MB. The memory size is contained in a structure created by an sclp call. The kernel accesses the field with a LH instrution which performs a sign extension of a 16 bit word. In the case of a memory size with bit 2^15 set this results in a very large value and the memory detection just loops for a long time. In addition if more then 64 GB are used on a 64 bit system the memory size is read from an incorrect storage location. Use zero-extention to read the 16 bit memory size and the correct offset to read the 4 byte memory size on 64 bit. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index b804c55..658e8de 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -517,10 +517,10 @@ startup:basr %r13,0 # get base l %r2, .Lrcp2-.LPG1(%r13) # try with Read SCP b .Lservicecall-.LPG1(%r13) .Lprocsccb: - lh %r1,.Lscpincr1-PARMAREA(%r4) # use this one if != 0 - chi %r1,0x00 - jne .Lscnd - l %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one + lhi %r1,0 + icm %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0 + jnz .Lscnd + l %r1,.Lscpincr2-PARMAREA+4(%r4) # otherwise use this one .Lscnd: xr %r3,%r3 # same logic ic %r3,.Lscpa1-PARMAREA(%r4) diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 8366793..8e2caf9 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -518,9 +518,9 @@ startup:basr %r13,0 # get base l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP b .Lservicecall-.LPG1(%r13) .Lprocsccb: - lh %r1,.Lscpincr1-PARMAREA(%r4) # use this one if != 0 - chi %r1,0x00 - jne .Lscnd + lghi %r1,0 + icm %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0 + jnz .Lscnd lg %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one .Lscnd: xr %r3,%r3 # same logic -- cgit v0.10.2 From 2b071886170df456e230c38a3e504da4a11fff79 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 21 Jun 2005 17:16:31 -0700 Subject: [PATCH] s390: pending interrupt after ipl from reader Wait for interrupt and clear status pending after resetting the reader. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 658e8de..fc8bf5e 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -345,10 +345,25 @@ iplstart: bno .Lnoreset la %r2,.Lreset lhi %r3,26 - .long 0x83230008 + diag %r2,%r3,8 + mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw +.Lwaitrdrirq: + lpsw .Lrdrwaitpsw +.Lrdrint: + c %r1,0xb8 # compare subchannel number + bne .Lwaitrdrirq + la %r5,.Lirb + tsch 0(%r5) .Lnoreset: + b .Lnoload + + .align 8 +.Lrdrnewpsw: + .long 0x00080000,0x80000000+.Lrdrint +.Lrdrwaitpsw: + .long 0x020a0000,0x80000000+.Lrdrint #endif - + # # everything loaded, go for it # diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 8e2caf9..f525c0c 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -344,10 +344,25 @@ iplstart: bno .Lnoreset la %r2,.Lreset lhi %r3,26 - .long 0x83230008 + diag %r2,%r3,8 + mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw +.Lwaitrdrirq: + lpsw .Lrdrwaitpsw +.Lrdrint: + c %r1,0xb8 # compare subchannel number + bne .Lwaitrdrirq + la %r5,.Lirb + tsch 0(%r5) .Lnoreset: + b .Lnoload + + .align 8 +.Lrdrnewpsw: + .long 0x00080000,0x80000000+.Lrdrint +.Lrdrwaitpsw: + .long 0x020a0000,0x80000000+.Lrdrint #endif - + # # everything loaded, go for it # -- cgit v0.10.2 From f5ccc842318efcd7c05dee3203dfdbbafae47bd6 Mon Sep 17 00:00:00 2001 From: Max Asbock Date: Tue, 21 Jun 2005 17:16:32 -0700 Subject: [PATCH] ibmasm driver: fix command buffer size First of a series of patches for the ibmasm driver. (that is the driver for the IBM xSeries RSA service processor) To summarize what they do: [1] change a #define for the buffer size for commands [2] Fix a bug where threads in the event handling code calling wait_event_interruptible() weren't woken up as expected. [3] Redesigned how remote mouse and keyboard events received by the driver are handled. [4] Fixed a race in the command reference counting logic. This patch: - change a #define for the buffer size for commands Signed-off-by: Max Asbock Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h index 6fec7fd..1e83406 100644 --- a/drivers/misc/ibmasm/ibmasm.h +++ b/drivers/misc/ibmasm/ibmasm.h @@ -52,7 +52,7 @@ #define IBMASM_CMD_TIMEOUT_NORMAL 45 #define IBMASM_CMD_TIMEOUT_EXTRA 240 -#define IBMASM_CMD_MAX_BUFFER_SIZE 0x4000 +#define IBMASM_CMD_MAX_BUFFER_SIZE 0x8000 #define REVERSE_HEARTBEAT_TIMEOUT 120 -- cgit v0.10.2 From b8acb808468a88a188d7c5aba3681c583a5785f9 Mon Sep 17 00:00:00 2001 From: Max Asbock Date: Tue, 21 Jun 2005 17:16:33 -0700 Subject: [PATCH] ibmasm driver: correctly wake up sleeping threads Due to my incomplete understanding of the wait_event_interruptible() function threads waiting for service processor events were not woken up. This patch fixes that problem. Signed-off-by: Max Asbock Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/misc/ibmasm/event.c b/drivers/misc/ibmasm/event.c index e100f34..fe1e819 100644 --- a/drivers/misc/ibmasm/event.c +++ b/drivers/misc/ibmasm/event.c @@ -23,6 +23,7 @@ */ #include "ibmasm.h" +#include "lowlevel.h" /* * ASM service processor event handling routines. @@ -34,7 +35,6 @@ * circular buffer. */ - static void wake_up_event_readers(struct service_processor *sp) { struct event_reader *reader; @@ -63,7 +63,7 @@ void ibmasm_receive_event(struct service_processor *sp, void *data, unsigned int spin_lock_irqsave(&sp->lock, flags); /* copy the event into the next slot in the circular buffer */ event = &buffer->events[buffer->next_index]; - memcpy(event->data, data, data_size); + memcpy_fromio(event->data, data, data_size); event->data_size = data_size; event->serial_number = buffer->next_serial_number; @@ -93,7 +93,10 @@ int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *rea unsigned int index; unsigned long flags; - if (wait_event_interruptible(reader->wait, event_available(buffer, reader))) + reader->cancelled = 0; + + if (wait_event_interruptible(reader->wait, + event_available(buffer, reader) || reader->cancelled)) return -ERESTARTSYS; if (!event_available(buffer, reader)) @@ -116,6 +119,12 @@ int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *rea return event->data_size; } +void ibmasm_cancel_next_event(struct event_reader *reader) +{ + reader->cancelled = 1; + wake_up_interruptible(&reader->wait); +} + void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader) { unsigned long flags; @@ -131,8 +140,6 @@ void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_r { unsigned long flags; - wake_up_interruptible(&reader->wait); - spin_lock_irqsave(&sp->lock, flags); list_del(&reader->node); spin_unlock_irqrestore(&sp->lock, flags); @@ -164,6 +171,5 @@ int ibmasm_event_buffer_init(struct service_processor *sp) void ibmasm_event_buffer_exit(struct service_processor *sp) { - wake_up_event_readers(sp); kfree(sp->event_buffer); } diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h index 1e83406..35c4def 100644 --- a/drivers/misc/ibmasm/ibmasm.h +++ b/drivers/misc/ibmasm/ibmasm.h @@ -108,6 +108,7 @@ struct event_buffer { }; struct event_reader { + int cancelled; unsigned int next_serial_number; wait_queue_head_t wait; struct list_head node; @@ -185,6 +186,7 @@ extern void ibmasm_receive_event(struct service_processor *sp, void *data, unsi extern void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader); extern void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_reader *reader); extern int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader); +extern void ibmasm_cancel_next_event(struct event_reader *reader); /* heartbeat - from SP to OS */ extern void ibmasm_register_panic_notifier(void); diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 866e867..c87ef7d 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -374,6 +374,7 @@ static int event_file_open(struct inode *inode, struct file *file) ibmasm_event_reader_register(sp, &event_data->reader); event_data->sp = sp; + event_data->active = 0; file->private_data = event_data; return 0; } @@ -391,7 +392,9 @@ static ssize_t event_file_read(struct file *file, char __user *buf, size_t count { struct ibmasmfs_event_data *event_data = file->private_data; struct event_reader *reader = &event_data->reader; + struct service_processor *sp = event_data->sp; int ret; + unsigned long flags; if (*offset < 0) return -EINVAL; @@ -400,17 +403,32 @@ static ssize_t event_file_read(struct file *file, char __user *buf, size_t count if (*offset != 0) return 0; - ret = ibmasm_get_next_event(event_data->sp, reader); + spin_lock_irqsave(&sp->lock, flags); + if (event_data->active) { + spin_unlock_irqrestore(&sp->lock, flags); + return -EBUSY; + } + event_data->active = 1; + spin_unlock_irqrestore(&sp->lock, flags); + + ret = ibmasm_get_next_event(sp, reader); if (ret <= 0) - return ret; + goto out; - if (count < reader->data_size) - return -EINVAL; + if (count < reader->data_size) { + ret = -EINVAL; + goto out; + } - if (copy_to_user(buf, reader->data, reader->data_size)) - return -EFAULT; + if (copy_to_user(buf, reader->data, reader->data_size)) { + ret = -EFAULT; + goto out; + } + ret = reader->data_size; - return reader->data_size; +out: + event_data->active = 0; + return ret; } static ssize_t event_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) @@ -424,7 +442,7 @@ static ssize_t event_file_write(struct file *file, const char __user *buf, size_ if (*offset != 0) return 0; - wake_up_interruptible(&event_data->reader.wait); + ibmasm_cancel_next_event(&event_data->reader); return 0; } -- cgit v0.10.2 From 278d72ae8803ffcd16070c95fe1d53f4466dc741 Mon Sep 17 00:00:00 2001 From: Max Asbock Date: Tue, 21 Jun 2005 17:16:34 -0700 Subject: [PATCH] ibmasm driver: redesign handling of remote control events This patch rewrites the handling of remote control events. Rather than making them available from a special file in the ibmasmfs, now the events from the RSA card get translated into kernel input events and injected into the input subsystem. The driver now will generate two /dev/input/eventX nodes -- one for the keyboard and one for the mouse. The mouse node generates absolute events more like a touch pad than a mouse. Signed-off-by: Vernon Mauery Signed-off-by: Max Asbock Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h index 35c4def..653a7d0 100644 --- a/drivers/misc/ibmasm/ibmasm.h +++ b/drivers/misc/ibmasm/ibmasm.h @@ -34,16 +34,31 @@ #include #include #include +#include /* Driver identification */ #define DRIVER_NAME "ibmasm" -#define DRIVER_VERSION "0.4" -#define DRIVER_AUTHOR "Max Asbock" +#define DRIVER_VERSION "1.0" +#define DRIVER_AUTHOR "Max Asbock , Vernon Mauery " #define DRIVER_DESC "IBM ASM Service Processor Driver" #define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME) #define info(msg) printk(KERN_INFO "%s: " msg "\n", DRIVER_NAME) +extern int ibmasm_debug; +#define dbg(STR, ARGS...) \ + do { \ + if (ibmasm_debug) \ + printk(KERN_DEBUG STR , ##ARGS); \ + } while (0) + +static inline char *get_timestamp(char *buf) +{ + struct timeval now; + do_gettimeofday(&now); + sprintf(buf, "%lu.%lu", now.tv_sec, now.tv_usec); + return buf; +} #define IBMASM_CMD_PENDING 0 #define IBMASM_CMD_COMPLETE 1 @@ -121,41 +136,11 @@ struct reverse_heartbeat { unsigned int stopped; }; - -/* remote console events */ -struct mouse_event { - long x; - long y; - unsigned char buttons; - unsigned char transitions; +struct ibmasm_remote { + struct input_dev keybd_dev; + struct input_dev mouse_dev; }; -struct keyboard_event { - unsigned long key_code; - unsigned char key_down; -}; - -struct remote_event { - unsigned long type; - union { - struct mouse_event mouse; - struct keyboard_event keyboard; - } data; -}; - -#define DRIVER_REMOTE_QUEUE_SIZE 240 - -struct remote_queue { - struct remote_event *start; - struct remote_event *end; - struct remote_event *reader; - struct remote_event *writer; - unsigned int size; - int open; - wait_queue_head_t wait; -}; - - struct service_processor { struct list_head node; spinlock_t lock; @@ -168,7 +153,7 @@ struct service_processor { char dirname[IBMASM_NAME_SIZE]; char devname[IBMASM_NAME_SIZE]; unsigned int number; - struct remote_queue remote_queue; + struct ibmasm_remote *remote; int serial_line; struct device *dev; }; @@ -210,11 +195,9 @@ extern int ibmasm_send_i2o_message(struct service_processor *sp); extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs); /* remote console */ -extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp); -extern int ibmasm_init_remote_queue(struct service_processor *sp); -extern void ibmasm_free_remote_queue(struct service_processor *sp); -extern void ibmasm_advance_reader(struct remote_queue *q, unsigned int n); -extern size_t ibmasm_events_available(struct remote_queue *q); +extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp, struct pt_regs *regs); +extern int ibmasm_init_remote_input_dev(struct service_processor *sp); +extern void ibmasm_free_remote_input_dev(struct service_processor *sp); /* file system */ extern int ibmasmfs_register(void); diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index c87ef7d..ca83916 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -37,9 +37,7 @@ * | |-- event * | |-- reverse_heartbeat * | `-- remote_video - * | |-- connected * | |-- depth - * | |-- events * | |-- height * | `-- width * . @@ -50,9 +48,7 @@ * |-- event * |-- reverse_heartbeat * `-- remote_video - * |-- connected * |-- depth - * |-- events * |-- height * `-- width * @@ -75,14 +71,6 @@ * remote_video/width: control remote display settings * write: set value * read: read value - * - * remote_video/connected - * read: return "1" if web browser VNC java applet is connected, - * "0" otherwise - * - * remote_video/events - * read: sleep until a remote mouse or keyboard event occurs, then return - * then event. */ #include @@ -593,75 +581,6 @@ static ssize_t remote_settings_file_write(struct file *file, const char __user * return count; } -static int remote_event_file_open(struct inode *inode, struct file *file) -{ - struct service_processor *sp; - unsigned long flags; - struct remote_queue *q; - - file->private_data = inode->u.generic_ip; - sp = file->private_data; - q = &sp->remote_queue; - - /* allow only one event reader */ - spin_lock_irqsave(&sp->lock, flags); - if (q->open) { - spin_unlock_irqrestore(&sp->lock, flags); - return -EBUSY; - } - q->open = 1; - spin_unlock_irqrestore(&sp->lock, flags); - - enable_mouse_interrupts(sp); - - return 0; -} - -static int remote_event_file_close(struct inode *inode, struct file *file) -{ - struct service_processor *sp = file->private_data; - - disable_mouse_interrupts(sp); - wake_up_interruptible(&sp->remote_queue.wait); - sp->remote_queue.open = 0; - - return 0; -} - -static ssize_t remote_event_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset) -{ - struct service_processor *sp = file->private_data; - struct remote_queue *q = &sp->remote_queue; - size_t data_size; - struct remote_event *reader = q->reader; - size_t num_events; - - if (*offset < 0) - return -EINVAL; - if (count == 0 || count > 1024) - return 0; - if (*offset != 0) - return 0; - - if (wait_event_interruptible(q->wait, q->reader != q->writer)) - return -ERESTARTSYS; - - /* only get multiples of struct remote_event */ - num_events = min((count/sizeof(struct remote_event)), ibmasm_events_available(q)); - if (!num_events) - return 0; - - data_size = num_events * sizeof(struct remote_event); - - if (copy_to_user(buf, reader, data_size)) - return -EFAULT; - - ibmasm_advance_reader(q, num_events); - - return data_size; -} - - static struct file_operations command_fops = { .open = command_file_open, .release = command_file_close, @@ -690,12 +609,6 @@ static struct file_operations remote_settings_fops = { .write = remote_settings_file_write, }; -static struct file_operations remote_event_fops = { - .open = remote_event_file_open, - .release = remote_event_file_close, - .read = remote_event_file_read, -}; - static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root) { @@ -721,7 +634,5 @@ static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root) ibmasmfs_create_file(sb, remote_dir, "width", &remote_settings_fops, (void *)display_width(sp), S_IRUSR|S_IWUSR); ibmasmfs_create_file(sb, remote_dir, "height", &remote_settings_fops, (void *)display_height(sp), S_IRUSR|S_IWUSR); ibmasmfs_create_file(sb, remote_dir, "depth", &remote_settings_fops, (void *)display_depth(sp), S_IRUSR|S_IWUSR); - ibmasmfs_create_file(sb, remote_dir, "connected", &remote_settings_fops, (void *)vnc_status(sp), S_IRUSR); - ibmasmfs_create_file(sb, remote_dir, "events", &remote_event_fops, (void *)sp, S_IRUSR); } } diff --git a/drivers/misc/ibmasm/lowlevel.c b/drivers/misc/ibmasm/lowlevel.c index 5156de2..47949a2 100644 --- a/drivers/misc/ibmasm/lowlevel.c +++ b/drivers/misc/ibmasm/lowlevel.c @@ -46,8 +46,8 @@ int ibmasm_send_i2o_message(struct service_processor *sp) message = get_i2o_message(sp->base_address, mfa); - memcpy(&message->header, &header, sizeof(struct i2o_header)); - memcpy(&message->data, command->buffer, command_size); + memcpy_toio(&message->header, &header, sizeof(struct i2o_header)); + memcpy_toio(&message->data, command->buffer, command_size); set_mfa_inbound(sp->base_address, mfa); @@ -59,23 +59,27 @@ irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *reg u32 mfa; struct service_processor *sp = (struct service_processor *)dev_id; void __iomem *base_address = sp->base_address; + char tsbuf[32]; if (!sp_interrupt_pending(base_address)) return IRQ_NONE; + dbg("respond to interrupt at %s\n", get_timestamp(tsbuf)); + if (mouse_interrupt_pending(sp)) { - ibmasm_handle_mouse_interrupt(sp); - mfa = get_mfa_outbound(base_address); + ibmasm_handle_mouse_interrupt(sp, regs); clear_mouse_interrupt(sp); - set_mfa_outbound(base_address, mfa); - return IRQ_HANDLED; } mfa = get_mfa_outbound(base_address); if (valid_mfa(mfa)) { struct i2o_message *msg = get_i2o_message(base_address, mfa); ibmasm_receive_message(sp, &msg->data, incoming_data_size(msg)); - } + } else + dbg("didn't get a valid MFA\n"); + set_mfa_outbound(base_address, mfa); + dbg("finished interrupt at %s\n", get_timestamp(tsbuf)); + return IRQ_HANDLED; } diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 777432a..1fdf03f 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -56,17 +56,26 @@ #include "lowlevel.h" #include "remote.h" +int ibmasm_debug = 0; +module_param(ibmasm_debug, int , S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off"); + static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { - int err, result = -ENOMEM; + int result; struct service_processor *sp; - if ((err = pci_enable_device(pdev))) { - printk(KERN_ERR "%s: can't enable PCI device at %s\n", - DRIVER_NAME, pci_name(pdev)); - return err; + if ((result = pci_enable_device(pdev))) { + dev_err(&pdev->dev, "Failed to enable PCI device\n"); + return result; } + if ((result = pci_request_regions(pdev, DRIVER_NAME))) { + dev_err(&pdev->dev, "Failed to allocate PCI resources\n"); + goto error_resources; + } + /* vnc client won't work without bus-mastering */ + pci_set_master(pdev); sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL); if (sp == NULL) { @@ -76,6 +85,9 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi } memset(sp, 0, sizeof(struct service_processor)); + sp->lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&sp->command_queue); + pci_set_drvdata(pdev, (void *)sp); sp->dev = &pdev->dev; sp->number = pdev->bus->number; @@ -101,15 +113,6 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi goto error_ioremap; } - result = ibmasm_init_remote_queue(sp); - if (result) { - dev_err(sp->dev, "Failed to initialize remote queue\n"); - goto error_remote_queue; - } - - spin_lock_init(&sp->lock); - INIT_LIST_HEAD(&sp->command_queue); - result = request_irq(sp->irq, ibmasm_interrupt_handler, SA_SHIRQ, sp->devname, (void*)sp); if (result) { dev_err(sp->dev, "Failed to register interrupt handler\n"); @@ -117,7 +120,12 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi } enable_sp_interrupts(sp->base_address); - disable_mouse_interrupts(sp); + + result = ibmasm_init_remote_input_dev(sp); + if (result) { + dev_err(sp->dev, "Failed to initialize remote queue\n"); + goto error_send_message; + } result = ibmasm_send_driver_vpd(sp); if (result) { @@ -133,30 +141,25 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi ibmasm_register_uart(sp); - dev_printk(KERN_DEBUG, &pdev->dev, "WARNING: This software may not be supported or function\n"); - dev_printk(KERN_DEBUG, &pdev->dev, "correctly on your IBM server. Please consult the IBM\n"); - dev_printk(KERN_DEBUG, &pdev->dev, "ServerProven website\n"); - dev_printk(KERN_DEBUG, &pdev->dev, "http://www.pc.ibm.com/ww/eserver/xseries/serverproven\n"); - dev_printk(KERN_DEBUG, &pdev->dev, "for information on the specific driver level and support\n"); - dev_printk(KERN_DEBUG, &pdev->dev, "statement for your IBM server.\n"); - return 0; error_send_message: disable_sp_interrupts(sp->base_address); + ibmasm_free_remote_input_dev(sp); free_irq(sp->irq, (void *)sp); error_request_irq: - ibmasm_free_remote_queue(sp); -error_remote_queue: iounmap(sp->base_address); error_ioremap: ibmasm_heartbeat_exit(sp); error_heartbeat: ibmasm_event_buffer_exit(sp); error_eventbuffer: + pci_set_drvdata(pdev, NULL); kfree(sp); error_kmalloc: - pci_disable_device(pdev); + pci_release_regions(pdev); +error_resources: + pci_disable_device(pdev); return result; } @@ -165,16 +168,24 @@ static void __devexit ibmasm_remove_one(struct pci_dev *pdev) { struct service_processor *sp = (struct service_processor *)pci_get_drvdata(pdev); + dbg("Unregistering UART\n"); ibmasm_unregister_uart(sp); - ibmasm_send_os_state(sp, SYSTEM_STATE_OS_DOWN); + dbg("Sending OS down message\n"); + if (ibmasm_send_os_state(sp, SYSTEM_STATE_OS_DOWN)) + err("failed to get repsonse to 'Send OS State' command\n"); + dbg("Disabling heartbeats\n"); + ibmasm_heartbeat_exit(sp); + dbg("Disabling interrupts\n"); disable_sp_interrupts(sp->base_address); - disable_mouse_interrupts(sp); + dbg("Freeing SP irq\n"); free_irq(sp->irq, (void *)sp); - ibmasm_heartbeat_exit(sp); - ibmasm_free_remote_queue(sp); + dbg("Cleaning up\n"); + ibmasm_free_remote_input_dev(sp); iounmap(sp->base_address); ibmasm_event_buffer_exit(sp); + pci_set_drvdata(pdev, NULL); kfree(sp); + pci_release_regions(pdev); pci_disable_device(pdev); } diff --git a/drivers/misc/ibmasm/remote.c b/drivers/misc/ibmasm/remote.c index 520c3f1..d3c48d2 100644 --- a/drivers/misc/ibmasm/remote.c +++ b/drivers/misc/ibmasm/remote.c @@ -1,4 +1,3 @@ - /* * IBM ASM Service Processor Device Driver * @@ -18,135 +17,256 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Authors: Max Asböck + * Vernon Mauery * */ /* Remote mouse and keyboard event handling functions */ +#include #include "ibmasm.h" #include "remote.h" -int ibmasm_init_remote_queue(struct service_processor *sp) -{ - struct remote_queue *q = &sp->remote_queue; - - disable_mouse_interrupts(sp); +static int xmax = 1600; +static int ymax = 1200; - q->open = 0; - q->size = 0; - q->start = kmalloc(DRIVER_REMOTE_QUEUE_SIZE * sizeof(struct remote_event), GFP_KERNEL); - if (q->start == 0) - return -ENOMEM; +static unsigned short xlate_high[XLATE_SIZE] = { + [KEY_SYM_ENTER & 0xff] = KEY_ENTER, + [KEY_SYM_KPSLASH & 0xff] = KEY_KPSLASH, + [KEY_SYM_KPSTAR & 0xff] = KEY_KPASTERISK, + [KEY_SYM_KPMINUS & 0xff] = KEY_KPMINUS, + [KEY_SYM_KPDOT & 0xff] = KEY_KPDOT, + [KEY_SYM_KPPLUS & 0xff] = KEY_KPPLUS, + [KEY_SYM_KP0 & 0xff] = KEY_KP0, + [KEY_SYM_KP1 & 0xff] = KEY_KP1, + [KEY_SYM_KP2 & 0xff] = KEY_KP2, [KEY_SYM_KPDOWN & 0xff] = KEY_KP2, + [KEY_SYM_KP3 & 0xff] = KEY_KP3, + [KEY_SYM_KP4 & 0xff] = KEY_KP4, [KEY_SYM_KPLEFT & 0xff] = KEY_KP4, + [KEY_SYM_KP5 & 0xff] = KEY_KP5, + [KEY_SYM_KP6 & 0xff] = KEY_KP6, [KEY_SYM_KPRIGHT & 0xff] = KEY_KP6, + [KEY_SYM_KP7 & 0xff] = KEY_KP7, + [KEY_SYM_KP8 & 0xff] = KEY_KP8, [KEY_SYM_KPUP & 0xff] = KEY_KP8, + [KEY_SYM_KP9 & 0xff] = KEY_KP9, + [KEY_SYM_BK_SPC & 0xff] = KEY_BACKSPACE, + [KEY_SYM_TAB & 0xff] = KEY_TAB, + [KEY_SYM_CTRL & 0xff] = KEY_LEFTCTRL, + [KEY_SYM_ALT & 0xff] = KEY_LEFTALT, + [KEY_SYM_INSERT & 0xff] = KEY_INSERT, + [KEY_SYM_DELETE & 0xff] = KEY_DELETE, + [KEY_SYM_SHIFT & 0xff] = KEY_LEFTSHIFT, + [KEY_SYM_UARROW & 0xff] = KEY_UP, + [KEY_SYM_DARROW & 0xff] = KEY_DOWN, + [KEY_SYM_LARROW & 0xff] = KEY_LEFT, + [KEY_SYM_RARROW & 0xff] = KEY_RIGHT, + [KEY_SYM_ESCAPE & 0xff] = KEY_ESC, + [KEY_SYM_PAGEUP & 0xff] = KEY_PAGEUP, + [KEY_SYM_PAGEDOWN & 0xff] = KEY_PAGEDOWN, + [KEY_SYM_HOME & 0xff] = KEY_HOME, + [KEY_SYM_END & 0xff] = KEY_END, + [KEY_SYM_F1 & 0xff] = KEY_F1, + [KEY_SYM_F2 & 0xff] = KEY_F2, + [KEY_SYM_F3 & 0xff] = KEY_F3, + [KEY_SYM_F4 & 0xff] = KEY_F4, + [KEY_SYM_F5 & 0xff] = KEY_F5, + [KEY_SYM_F6 & 0xff] = KEY_F6, + [KEY_SYM_F7 & 0xff] = KEY_F7, + [KEY_SYM_F8 & 0xff] = KEY_F8, + [KEY_SYM_F9 & 0xff] = KEY_F9, + [KEY_SYM_F10 & 0xff] = KEY_F10, + [KEY_SYM_F11 & 0xff] = KEY_F11, + [KEY_SYM_F12 & 0xff] = KEY_F12, + [KEY_SYM_CAP_LOCK & 0xff] = KEY_CAPSLOCK, + [KEY_SYM_NUM_LOCK & 0xff] = KEY_NUMLOCK, + [KEY_SYM_SCR_LOCK & 0xff] = KEY_SCROLLLOCK, +}; +static unsigned short xlate[XLATE_SIZE] = { + [NO_KEYCODE] = KEY_RESERVED, + [KEY_SYM_SPACE] = KEY_SPACE, + [KEY_SYM_TILDE] = KEY_GRAVE, [KEY_SYM_BKTIC] = KEY_GRAVE, + [KEY_SYM_ONE] = KEY_1, [KEY_SYM_BANG] = KEY_1, + [KEY_SYM_TWO] = KEY_2, [KEY_SYM_AT] = KEY_2, + [KEY_SYM_THREE] = KEY_3, [KEY_SYM_POUND] = KEY_3, + [KEY_SYM_FOUR] = KEY_4, [KEY_SYM_DOLLAR] = KEY_4, + [KEY_SYM_FIVE] = KEY_5, [KEY_SYM_PERCENT] = KEY_5, + [KEY_SYM_SIX] = KEY_6, [KEY_SYM_CARAT] = KEY_6, + [KEY_SYM_SEVEN] = KEY_7, [KEY_SYM_AMPER] = KEY_7, + [KEY_SYM_EIGHT] = KEY_8, [KEY_SYM_STAR] = KEY_8, + [KEY_SYM_NINE] = KEY_9, [KEY_SYM_LPAREN] = KEY_9, + [KEY_SYM_ZERO] = KEY_0, [KEY_SYM_RPAREN] = KEY_0, + [KEY_SYM_MINUS] = KEY_MINUS, [KEY_SYM_USCORE] = KEY_MINUS, + [KEY_SYM_EQUAL] = KEY_EQUAL, [KEY_SYM_PLUS] = KEY_EQUAL, + [KEY_SYM_LBRKT] = KEY_LEFTBRACE, [KEY_SYM_LCURLY] = KEY_LEFTBRACE, + [KEY_SYM_RBRKT] = KEY_RIGHTBRACE, [KEY_SYM_RCURLY] = KEY_RIGHTBRACE, + [KEY_SYM_SLASH] = KEY_BACKSLASH, [KEY_SYM_PIPE] = KEY_BACKSLASH, + [KEY_SYM_TIC] = KEY_APOSTROPHE, [KEY_SYM_QUOTE] = KEY_APOSTROPHE, + [KEY_SYM_SEMIC] = KEY_SEMICOLON, [KEY_SYM_COLON] = KEY_SEMICOLON, + [KEY_SYM_COMMA] = KEY_COMMA, [KEY_SYM_LT] = KEY_COMMA, + [KEY_SYM_PERIOD] = KEY_DOT, [KEY_SYM_GT] = KEY_DOT, + [KEY_SYM_BSLASH] = KEY_SLASH, [KEY_SYM_QMARK] = KEY_SLASH, + [KEY_SYM_A] = KEY_A, [KEY_SYM_a] = KEY_A, + [KEY_SYM_B] = KEY_B, [KEY_SYM_b] = KEY_B, + [KEY_SYM_C] = KEY_C, [KEY_SYM_c] = KEY_C, + [KEY_SYM_D] = KEY_D, [KEY_SYM_d] = KEY_D, + [KEY_SYM_E] = KEY_E, [KEY_SYM_e] = KEY_E, + [KEY_SYM_F] = KEY_F, [KEY_SYM_f] = KEY_F, + [KEY_SYM_G] = KEY_G, [KEY_SYM_g] = KEY_G, + [KEY_SYM_H] = KEY_H, [KEY_SYM_h] = KEY_H, + [KEY_SYM_I] = KEY_I, [KEY_SYM_i] = KEY_I, + [KEY_SYM_J] = KEY_J, [KEY_SYM_j] = KEY_J, + [KEY_SYM_K] = KEY_K, [KEY_SYM_k] = KEY_K, + [KEY_SYM_L] = KEY_L, [KEY_SYM_l] = KEY_L, + [KEY_SYM_M] = KEY_M, [KEY_SYM_m] = KEY_M, + [KEY_SYM_N] = KEY_N, [KEY_SYM_n] = KEY_N, + [KEY_SYM_O] = KEY_O, [KEY_SYM_o] = KEY_O, + [KEY_SYM_P] = KEY_P, [KEY_SYM_p] = KEY_P, + [KEY_SYM_Q] = KEY_Q, [KEY_SYM_q] = KEY_Q, + [KEY_SYM_R] = KEY_R, [KEY_SYM_r] = KEY_R, + [KEY_SYM_S] = KEY_S, [KEY_SYM_s] = KEY_S, + [KEY_SYM_T] = KEY_T, [KEY_SYM_t] = KEY_T, + [KEY_SYM_U] = KEY_U, [KEY_SYM_u] = KEY_U, + [KEY_SYM_V] = KEY_V, [KEY_SYM_v] = KEY_V, + [KEY_SYM_W] = KEY_W, [KEY_SYM_w] = KEY_W, + [KEY_SYM_X] = KEY_X, [KEY_SYM_x] = KEY_X, + [KEY_SYM_Y] = KEY_Y, [KEY_SYM_y] = KEY_Y, + [KEY_SYM_Z] = KEY_Z, [KEY_SYM_z] = KEY_Z, +}; - q->end = q->start + DRIVER_REMOTE_QUEUE_SIZE; - q->reader = q->start; - q->writer = q->start; - q->size = DRIVER_REMOTE_QUEUE_SIZE; - init_waitqueue_head(&q->wait); +static char remote_mouse_name[] = "ibmasm RSA I remote mouse"; +static char remote_keybd_name[] = "ibmasm RSA I remote keyboard"; - return 0; -} - -void ibmasm_free_remote_queue(struct service_processor *sp) +static void print_input(struct remote_input *input) { - kfree(sp->remote_queue.start); + if (input->type == INPUT_TYPE_MOUSE) { + unsigned char buttons = input->mouse_buttons; + dbg("remote mouse movement: (x,y)=(%d,%d)%s%s%s%s\n", + input->data.mouse.x, input->data.mouse.y, + (buttons)?" -- buttons:":"", + (buttons & REMOTE_BUTTON_LEFT)?"left ":"", + (buttons & REMOTE_BUTTON_MIDDLE)?"middle ":"", + (buttons & REMOTE_BUTTON_RIGHT)?"right":"" + ); + } else { + dbg("remote keypress (code, flag, down):" + "%d (0x%x) [0x%x] [0x%x]\n", + input->data.keyboard.key_code, + input->data.keyboard.key_code, + input->data.keyboard.key_flag, + input->data.keyboard.key_down + ); + } } -void ibmasm_advance_reader(struct remote_queue *q, unsigned int n) +static void send_mouse_event(struct input_dev *dev, struct pt_regs *regs, + struct remote_input *input) { - q->reader += n; - if (q->reader >= q->end) - q->reader -= q->size; -} + unsigned char buttons = input->mouse_buttons; -size_t ibmasm_events_available(struct remote_queue *q) -{ - ssize_t diff = q->writer - q->reader; - - return (diff >= 0) ? diff : q->end - q->reader; + input_regs(dev, regs); + input_report_abs(dev, ABS_X, input->data.mouse.x); + input_report_abs(dev, ABS_Y, input->data.mouse.y); + input_report_key(dev, BTN_LEFT, buttons & REMOTE_BUTTON_LEFT); + input_report_key(dev, BTN_MIDDLE, buttons & REMOTE_BUTTON_MIDDLE); + input_report_key(dev, BTN_RIGHT, buttons & REMOTE_BUTTON_RIGHT); + input_sync(dev); } - -static int space_free(struct remote_queue *q) +static void send_keyboard_event(struct input_dev *dev, struct pt_regs *regs, + struct remote_input *input) { - if (q->reader == q->writer) - return q->size - 1; + unsigned int key; + unsigned short code = input->data.keyboard.key_code; - return ( (q->reader + q->size - q->writer) % q->size ) - 1; + if (code & 0xff00) + key = xlate_high[code & 0xff]; + else + key = xlate[code]; + input_regs(dev, regs); + input_report_key(dev, key, (input->data.keyboard.key_down) ? 1 : 0); + input_sync(dev); } -static void set_mouse_event(struct remote_input *input, struct mouse_event *mouse) +void ibmasm_handle_mouse_interrupt(struct service_processor *sp, + struct pt_regs *regs) { - static char last_buttons = 0; + unsigned long reader; + unsigned long writer; + struct remote_input input; - mouse->x = input->data.mouse.x; - mouse->y = input->data.mouse.y; + reader = get_queue_reader(sp); + writer = get_queue_writer(sp); - if (input->mouse_buttons == REMOTE_MOUSE_DOUBLE_CLICK) { - mouse->buttons = REMOTE_MOUSE_DOUBLE_CLICK; - last_buttons = 0; - return; - } - mouse->transitions = last_buttons ^ input->mouse_buttons; - mouse->buttons = input->mouse_buttons; + while (reader != writer) { + memcpy_fromio(&input, get_queue_entry(sp, reader), + sizeof(struct remote_input)); - last_buttons = input->mouse_buttons; -} + print_input(&input); + if (input.type == INPUT_TYPE_MOUSE) { + send_mouse_event(&sp->remote->mouse_dev, regs, &input); + } else if (input.type == INPUT_TYPE_KEYBOARD) { + send_keyboard_event(&sp->remote->keybd_dev, regs, &input); + } else + break; -static void set_keyboard_event(struct remote_input *input, struct keyboard_event *keyboard) -{ - keyboard->key_code = input->data.keyboard.key_code; - keyboard->key_down = input->data.keyboard.key_down; + reader = advance_queue_reader(sp, reader); + writer = get_queue_writer(sp); + } } -static int add_to_driver_queue(struct remote_queue *q, struct remote_input *input) +int ibmasm_init_remote_input_dev(struct service_processor *sp) { - struct remote_event *event = q->writer; + /* set up the mouse input device */ + struct ibmasm_remote *remote; + struct pci_dev *pdev = to_pci_dev(sp->dev); + int i; - if (space_free(q) < 1) { - return 1; - } + sp->remote = remote = kmalloc(sizeof(*remote), GFP_KERNEL); + if (!remote) + return -ENOMEM; - switch(input->type) { - case (INPUT_TYPE_MOUSE): - event->type = INPUT_TYPE_MOUSE; - set_mouse_event(input, &event->data.mouse); - break; - case (INPUT_TYPE_KEYBOARD): - event->type = INPUT_TYPE_KEYBOARD; - set_keyboard_event(input, &event->data.keyboard); - break; - default: - return 0; - } - event->type = input->type; + memset(remote, 0, sizeof(*remote)); - q->writer++; - if (q->writer == q->end) - q->writer = q->start; + remote->mouse_dev.private = remote; + init_input_dev(&remote->mouse_dev); + remote->mouse_dev.id.vendor = pdev->vendor; + remote->mouse_dev.id.product = pdev->device; + remote->mouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + remote->mouse_dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | + BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + set_bit(BTN_TOUCH, remote->mouse_dev.keybit); + remote->mouse_dev.name = remote_mouse_name; + input_set_abs_params(&remote->mouse_dev, ABS_X, 0, xmax, 0, 0); + input_set_abs_params(&remote->mouse_dev, ABS_Y, 0, ymax, 0, 0); - return 0; -} - + remote->keybd_dev.private = remote; + init_input_dev(&remote->keybd_dev); + remote->keybd_dev.id.vendor = pdev->vendor; + remote->keybd_dev.id.product = pdev->device; + remote->keybd_dev.evbit[0] = BIT(EV_KEY); + remote->keybd_dev.name = remote_keybd_name; -void ibmasm_handle_mouse_interrupt(struct service_processor *sp) -{ - unsigned long reader; - unsigned long writer; - struct remote_input input; + for (i=0; ikeybd_dev.keybit); + if (xlate[i]) + set_bit(xlate[i], remote->keybd_dev.keybit); + } - reader = get_queue_reader(sp); - writer = get_queue_writer(sp); + input_register_device(&remote->mouse_dev); + input_register_device(&remote->keybd_dev); + enable_mouse_interrupts(sp); - while (reader != writer) { - memcpy(&input, (void *)get_queue_entry(sp, reader), sizeof(struct remote_input)); + printk(KERN_INFO "ibmasm remote responding to events on RSA card %d\n", sp->number); - if (add_to_driver_queue(&sp->remote_queue, &input)) - break; + return 0; +} - reader = advance_queue_reader(sp, reader); - } - wake_up_interruptible(&sp->remote_queue.wait); +void ibmasm_free_remote_input_dev(struct service_processor *sp) +{ + disable_mouse_interrupts(sp); + input_unregister_device(&sp->remote->keybd_dev); + input_unregister_device(&sp->remote->mouse_dev); + kfree(sp->remote); } + diff --git a/drivers/misc/ibmasm/remote.h b/drivers/misc/ibmasm/remote.h index a8eb19f..b7076a8 100644 --- a/drivers/misc/ibmasm/remote.h +++ b/drivers/misc/ibmasm/remote.h @@ -51,11 +51,13 @@ /* mouse button states received from SP */ -#define REMOTE_MOUSE_DOUBLE_CLICK 0xF0 -#define REMOTE_MOUSE_BUTTON_LEFT 0x01 -#define REMOTE_MOUSE_BUTTON_MIDDLE 0x02 -#define REMOTE_MOUSE_BUTTON_RIGHT 0x04 +#define REMOTE_DOUBLE_CLICK 0xF0 +#define REMOTE_BUTTON_LEFT 0x01 +#define REMOTE_BUTTON_MIDDLE 0x02 +#define REMOTE_BUTTON_RIGHT 0x04 +/* size of keysym/keycode translation matricies */ +#define XLATE_SIZE 256 struct mouse_input { unsigned short y; @@ -83,11 +85,13 @@ struct remote_input { unsigned char pad3; }; -#define mouse_addr(sp) sp->base_address + CONDOR_MOUSE_DATA -#define display_width(sp) mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESX -#define display_height(sp) mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESY -#define display_depth(sp) mouse_addr(sp) + CONDOR_INPUT_DISPLAY_BITS -#define vnc_status(sp) mouse_addr(sp) + CONDOR_OUTPUT_VNC_STATUS +#define mouse_addr(sp) (sp->base_address + CONDOR_MOUSE_DATA) +#define display_width(sp) (mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESX) +#define display_height(sp) (mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESY) +#define display_depth(sp) (mouse_addr(sp) + CONDOR_INPUT_DISPLAY_BITS) +#define desktop_info(sp) (mouse_addr(sp) + CONDOR_INPUT_DESKTOP_INFO) +#define vnc_status(sp) (mouse_addr(sp) + CONDOR_OUTPUT_VNC_STATUS) +#define isr_control(sp) (mouse_addr(sp) + CONDOR_MOUSE_ISR_CONTROL) #define mouse_interrupt_pending(sp) readl(mouse_addr(sp) + CONDOR_MOUSE_ISR_STATUS) #define clear_mouse_interrupt(sp) writel(0, mouse_addr(sp) + CONDOR_MOUSE_ISR_STATUS) @@ -101,10 +105,10 @@ struct remote_input { #define get_queue_reader(sp) readl(mouse_addr(sp) + CONDOR_MOUSE_Q_READER) #define set_queue_reader(sp, reader) writel(reader, mouse_addr(sp) + CONDOR_MOUSE_Q_READER) -#define queue_begin mouse_addr(sp) + CONDOR_MOUSE_Q_BEGIN +#define queue_begin (mouse_addr(sp) + CONDOR_MOUSE_Q_BEGIN) #define get_queue_entry(sp, read_index) \ - queue_begin + read_index * sizeof(struct remote_input) + ((void*)(queue_begin + read_index * sizeof(struct remote_input))) static inline int advance_queue_reader(struct service_processor *sp, unsigned long reader) { @@ -116,4 +120,151 @@ static inline int advance_queue_reader(struct service_processor *sp, unsigned lo return reader; } +#define NO_KEYCODE 0 +#define KEY_SYM_BK_SPC 0xFF08 +#define KEY_SYM_TAB 0xFF09 +#define KEY_SYM_ENTER 0xFF0D +#define KEY_SYM_SCR_LOCK 0xFF14 +#define KEY_SYM_ESCAPE 0xFF1B +#define KEY_SYM_HOME 0xFF50 +#define KEY_SYM_LARROW 0xFF51 +#define KEY_SYM_UARROW 0xFF52 +#define KEY_SYM_RARROW 0xFF53 +#define KEY_SYM_DARROW 0xFF54 +#define KEY_SYM_PAGEUP 0xFF55 +#define KEY_SYM_PAGEDOWN 0xFF56 +#define KEY_SYM_END 0xFF57 +#define KEY_SYM_INSERT 0xFF63 +#define KEY_SYM_NUM_LOCK 0xFF7F +#define KEY_SYM_KPSTAR 0xFFAA +#define KEY_SYM_KPPLUS 0xFFAB +#define KEY_SYM_KPMINUS 0xFFAD +#define KEY_SYM_KPDOT 0xFFAE +#define KEY_SYM_KPSLASH 0xFFAF +#define KEY_SYM_KPRIGHT 0xFF96 +#define KEY_SYM_KPUP 0xFF97 +#define KEY_SYM_KPLEFT 0xFF98 +#define KEY_SYM_KPDOWN 0xFF99 +#define KEY_SYM_KP0 0xFFB0 +#define KEY_SYM_KP1 0xFFB1 +#define KEY_SYM_KP2 0xFFB2 +#define KEY_SYM_KP3 0xFFB3 +#define KEY_SYM_KP4 0xFFB4 +#define KEY_SYM_KP5 0xFFB5 +#define KEY_SYM_KP6 0xFFB6 +#define KEY_SYM_KP7 0xFFB7 +#define KEY_SYM_KP8 0xFFB8 +#define KEY_SYM_KP9 0xFFB9 +#define KEY_SYM_F1 0xFFBE // 1B 5B 5B 41 +#define KEY_SYM_F2 0xFFBF // 1B 5B 5B 42 +#define KEY_SYM_F3 0xFFC0 // 1B 5B 5B 43 +#define KEY_SYM_F4 0xFFC1 // 1B 5B 5B 44 +#define KEY_SYM_F5 0xFFC2 // 1B 5B 5B 45 +#define KEY_SYM_F6 0xFFC3 // 1B 5B 31 37 7E +#define KEY_SYM_F7 0xFFC4 // 1B 5B 31 38 7E +#define KEY_SYM_F8 0xFFC5 // 1B 5B 31 39 7E +#define KEY_SYM_F9 0xFFC6 // 1B 5B 32 30 7E +#define KEY_SYM_F10 0xFFC7 // 1B 5B 32 31 7E +#define KEY_SYM_F11 0xFFC8 // 1B 5B 32 33 7E +#define KEY_SYM_F12 0xFFC9 // 1B 5B 32 34 7E +#define KEY_SYM_SHIFT 0xFFE1 +#define KEY_SYM_CTRL 0xFFE3 +#define KEY_SYM_ALT 0xFFE9 +#define KEY_SYM_CAP_LOCK 0xFFE5 +#define KEY_SYM_DELETE 0xFFFF +#define KEY_SYM_TILDE 0x60 +#define KEY_SYM_BKTIC 0x7E +#define KEY_SYM_ONE 0x31 +#define KEY_SYM_BANG 0x21 +#define KEY_SYM_TWO 0x32 +#define KEY_SYM_AT 0x40 +#define KEY_SYM_THREE 0x33 +#define KEY_SYM_POUND 0x23 +#define KEY_SYM_FOUR 0x34 +#define KEY_SYM_DOLLAR 0x24 +#define KEY_SYM_FIVE 0x35 +#define KEY_SYM_PERCENT 0x25 +#define KEY_SYM_SIX 0x36 +#define KEY_SYM_CARAT 0x5E +#define KEY_SYM_SEVEN 0x37 +#define KEY_SYM_AMPER 0x26 +#define KEY_SYM_EIGHT 0x38 +#define KEY_SYM_STAR 0x2A +#define KEY_SYM_NINE 0x39 +#define KEY_SYM_LPAREN 0x28 +#define KEY_SYM_ZERO 0x30 +#define KEY_SYM_RPAREN 0x29 +#define KEY_SYM_MINUS 0x2D +#define KEY_SYM_USCORE 0x5F +#define KEY_SYM_EQUAL 0x2B +#define KEY_SYM_PLUS 0x3D +#define KEY_SYM_LBRKT 0x5B +#define KEY_SYM_LCURLY 0x7B +#define KEY_SYM_RBRKT 0x5D +#define KEY_SYM_RCURLY 0x7D +#define KEY_SYM_SLASH 0x5C +#define KEY_SYM_PIPE 0x7C +#define KEY_SYM_TIC 0x27 +#define KEY_SYM_QUOTE 0x22 +#define KEY_SYM_SEMIC 0x3B +#define KEY_SYM_COLON 0x3A +#define KEY_SYM_COMMA 0x2C +#define KEY_SYM_LT 0x3C +#define KEY_SYM_PERIOD 0x2E +#define KEY_SYM_GT 0x3E +#define KEY_SYM_BSLASH 0x2F +#define KEY_SYM_QMARK 0x3F +#define KEY_SYM_A 0x41 +#define KEY_SYM_B 0x42 +#define KEY_SYM_C 0x43 +#define KEY_SYM_D 0x44 +#define KEY_SYM_E 0x45 +#define KEY_SYM_F 0x46 +#define KEY_SYM_G 0x47 +#define KEY_SYM_H 0x48 +#define KEY_SYM_I 0x49 +#define KEY_SYM_J 0x4A +#define KEY_SYM_K 0x4B +#define KEY_SYM_L 0x4C +#define KEY_SYM_M 0x4D +#define KEY_SYM_N 0x4E +#define KEY_SYM_O 0x4F +#define KEY_SYM_P 0x50 +#define KEY_SYM_Q 0x51 +#define KEY_SYM_R 0x52 +#define KEY_SYM_S 0x53 +#define KEY_SYM_T 0x54 +#define KEY_SYM_U 0x55 +#define KEY_SYM_V 0x56 +#define KEY_SYM_W 0x57 +#define KEY_SYM_X 0x58 +#define KEY_SYM_Y 0x59 +#define KEY_SYM_Z 0x5A +#define KEY_SYM_a 0x61 +#define KEY_SYM_b 0x62 +#define KEY_SYM_c 0x63 +#define KEY_SYM_d 0x64 +#define KEY_SYM_e 0x65 +#define KEY_SYM_f 0x66 +#define KEY_SYM_g 0x67 +#define KEY_SYM_h 0x68 +#define KEY_SYM_i 0x69 +#define KEY_SYM_j 0x6A +#define KEY_SYM_k 0x6B +#define KEY_SYM_l 0x6C +#define KEY_SYM_m 0x6D +#define KEY_SYM_n 0x6E +#define KEY_SYM_o 0x6F +#define KEY_SYM_p 0x70 +#define KEY_SYM_q 0x71 +#define KEY_SYM_r 0x72 +#define KEY_SYM_s 0x73 +#define KEY_SYM_t 0x74 +#define KEY_SYM_u 0x75 +#define KEY_SYM_v 0x76 +#define KEY_SYM_w 0x77 +#define KEY_SYM_x 0x78 +#define KEY_SYM_y 0x79 +#define KEY_SYM_z 0x7A +#define KEY_SYM_SPACE 0x20 #endif /* _IBMASM_REMOTE_H_ */ -- cgit v0.10.2 From 8818760512424f60ad9fafb7a087b007a9274eb3 Mon Sep 17 00:00:00 2001 From: Max Asbock Date: Tue, 21 Jun 2005 17:16:36 -0700 Subject: [PATCH] ibmasm driver: fix race in command refcount logic This patch fixes a race in the command reference counting logic by putting spinlocks around kobject_put() in the command_put function. - Also added debug messages. - Changed a memcpy to memcpy_fromio since we are reading from io space. Signed-off-by: Max Asbock Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c index 245b005..07a085c 100644 --- a/drivers/misc/ibmasm/command.c +++ b/drivers/misc/ibmasm/command.c @@ -23,6 +23,7 @@ */ #include "ibmasm.h" +#include "lowlevel.h" static void exec_next_command(struct service_processor *sp); static void free_command(struct kobject *kobj); @@ -31,8 +32,9 @@ static struct kobj_type ibmasm_cmd_kobj_type = { .release = free_command, }; +static atomic_t command_count = ATOMIC_INIT(0); -struct command *ibmasm_new_command(size_t buffer_size) +struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size) { struct command *cmd; @@ -55,11 +57,15 @@ struct command *ibmasm_new_command(size_t buffer_size) kobject_init(&cmd->kobj); cmd->kobj.ktype = &ibmasm_cmd_kobj_type; + cmd->lock = &sp->lock; cmd->status = IBMASM_CMD_PENDING; init_waitqueue_head(&cmd->wait); INIT_LIST_HEAD(&cmd->queue_node); + atomic_inc(&command_count); + dbg("command count: %d\n", atomic_read(&command_count)); + return cmd; } @@ -68,6 +74,8 @@ static void free_command(struct kobject *kobj) struct command *cmd = to_command(kobj); list_del(&cmd->queue_node); + atomic_dec(&command_count); + dbg("command count: %d\n", atomic_read(&command_count)); kfree(cmd->buffer); kfree(cmd); } @@ -94,8 +102,14 @@ static struct command *dequeue_command(struct service_processor *sp) static inline void do_exec_command(struct service_processor *sp) { + char tsbuf[32]; + + dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + if (ibmasm_send_i2o_message(sp)) { sp->current_command->status = IBMASM_CMD_FAILED; + wake_up(&sp->current_command->wait); + command_put(sp->current_command); exec_next_command(sp); } } @@ -111,14 +125,16 @@ static inline void do_exec_command(struct service_processor *sp) void ibmasm_exec_command(struct service_processor *sp, struct command *cmd) { unsigned long flags; + char tsbuf[32]; + + dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); spin_lock_irqsave(&sp->lock, flags); if (!sp->current_command) { - command_get(cmd); sp->current_command = cmd; + command_get(sp->current_command); spin_unlock_irqrestore(&sp->lock, flags); - do_exec_command(sp); } else { enqueue_command(sp, cmd); @@ -129,9 +145,9 @@ void ibmasm_exec_command(struct service_processor *sp, struct command *cmd) static void exec_next_command(struct service_processor *sp) { unsigned long flags; + char tsbuf[32]; - wake_up(&sp->current_command->wait); - command_put(sp->current_command); + dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); spin_lock_irqsave(&sp->lock, flags); sp->current_command = dequeue_command(sp); @@ -169,7 +185,9 @@ void ibmasm_receive_command_response(struct service_processor *sp, void *respons if (!sp->current_command) return; - memcpy(cmd->buffer, response, min(size, cmd->buffer_size)); + memcpy_fromio(cmd->buffer, response, min(size, cmd->buffer_size)); cmd->status = IBMASM_CMD_COMPLETE; + wake_up(&sp->current_command->wait); + command_put(sp->current_command); exec_next_command(sp); } diff --git a/drivers/misc/ibmasm/dot_command.c b/drivers/misc/ibmasm/dot_command.c index 478a8d8..13c52f8 100644 --- a/drivers/misc/ibmasm/dot_command.c +++ b/drivers/misc/ibmasm/dot_command.c @@ -33,7 +33,13 @@ void ibmasm_receive_message(struct service_processor *sp, void *message, int mes u32 size; struct dot_command_header *header = (struct dot_command_header *)message; + if (message_size == 0) + return; + size = get_dot_command_size(message); + if (size == 0) + return; + if (size > message_size) size = message_size; @@ -67,7 +73,7 @@ int ibmasm_send_driver_vpd(struct service_processor *sp) u8 *vpd_data; int result = 0; - command = ibmasm_new_command(INIT_BUFFER_SIZE); + command = ibmasm_new_command(sp, INIT_BUFFER_SIZE); if (command == NULL) return -ENOMEM; @@ -121,7 +127,7 @@ int ibmasm_send_os_state(struct service_processor *sp, int os_state) struct os_state_command *os_state_cmd; int result = 0; - cmd = ibmasm_new_command(sizeof(struct os_state_command)); + cmd = ibmasm_new_command(sp, sizeof(struct os_state_command)); if (cmd == NULL) return -ENOMEM; diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c index ce09309..f295401 100644 --- a/drivers/misc/ibmasm/heartbeat.c +++ b/drivers/misc/ibmasm/heartbeat.c @@ -25,6 +25,7 @@ #include #include "ibmasm.h" #include "dot_command.h" +#include "lowlevel.h" static int suspend_heartbeats = 0; @@ -62,7 +63,7 @@ void ibmasm_unregister_panic_notifier(void) int ibmasm_heartbeat_init(struct service_processor *sp) { - sp->heartbeat = ibmasm_new_command(HEARTBEAT_BUFFER_SIZE); + sp->heartbeat = ibmasm_new_command(sp, HEARTBEAT_BUFFER_SIZE); if (sp->heartbeat == NULL) return -ENOMEM; @@ -71,6 +72,12 @@ int ibmasm_heartbeat_init(struct service_processor *sp) void ibmasm_heartbeat_exit(struct service_processor *sp) { + char tsbuf[32]; + + dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + ibmasm_wait_for_response(sp->heartbeat, IBMASM_CMD_TIMEOUT_NORMAL); + dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + suspend_heartbeats = 1; command_put(sp->heartbeat); } @@ -78,14 +85,16 @@ void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size { struct command *cmd = sp->heartbeat; struct dot_command_header *header = (struct dot_command_header *)cmd->buffer; + char tsbuf[32]; + dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); if (suspend_heartbeats) return; /* return the received dot command to sender */ cmd->status = IBMASM_CMD_PENDING; size = min(size, cmd->buffer_size); - memcpy(cmd->buffer, message, size); + memcpy_fromio(cmd->buffer, message, size); header->type = sp_write; ibmasm_exec_command(sp, cmd); } diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h index 653a7d0..ecce4ff 100644 --- a/drivers/misc/ibmasm/ibmasm.h +++ b/drivers/misc/ibmasm/ibmasm.h @@ -95,12 +95,17 @@ struct command { size_t buffer_size; int status; struct kobject kobj; + spinlock_t *lock; }; #define to_command(c) container_of(c, struct command, kobj) static inline void command_put(struct command *cmd) { + unsigned long flags; + + spin_lock_irqsave(cmd->lock, flags); kobject_put(&cmd->kobj); + spin_unlock_irqrestore(cmd->lock, flags); } static inline void command_get(struct command *cmd) @@ -159,7 +164,7 @@ struct service_processor { }; /* command processing */ -extern struct command *ibmasm_new_command(size_t buffer_size); +extern struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size); extern void ibmasm_exec_command(struct service_processor *sp, struct command *cmd); extern void ibmasm_wait_for_response(struct command *cmd, int timeout); extern void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size); diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index ca83916..5c550fc 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -321,7 +321,7 @@ static ssize_t command_file_write(struct file *file, const char __user *ubuff, s if (command_data->command) return -EAGAIN; - cmd = ibmasm_new_command(count); + cmd = ibmasm_new_command(command_data->sp, count); if (!cmd) return -ENOMEM; diff --git a/drivers/misc/ibmasm/r_heartbeat.c b/drivers/misc/ibmasm/r_heartbeat.c index 93d9c1b..f8fdb2d 100644 --- a/drivers/misc/ibmasm/r_heartbeat.c +++ b/drivers/misc/ibmasm/r_heartbeat.c @@ -63,7 +63,7 @@ int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_ int times_failed = 0; int result = 1; - cmd = ibmasm_new_command(sizeof rhb_dot_cmd); + cmd = ibmasm_new_command(sp, sizeof rhb_dot_cmd); if (!cmd) return -ENOMEM; -- cgit v0.10.2 From 9b1e3afd6d56937ced3914971621d0f053ea9178 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Tue, 21 Jun 2005 17:16:38 -0700 Subject: [PATCH] autofs4: avoid panic on bind mount of autofs owned directory While this is not a solution to bind and move mounts on autofs owned directories it is necessary to fix the trady error handling. At least it avoids the kernel panic I observed checking out bug #4589. Signed-off-by: Ian Kent Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index c7b2b88..9c09641 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -185,6 +185,19 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify); int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); void autofs4_catatonic_mode(struct autofs_sb_info *); +static inline int autofs4_follow_mount(struct vfsmount **mnt, struct dentry **dentry) +{ + int res = 0; + + while (d_mountpoint(*dentry)) { + int followed = follow_down(mnt, dentry); + if (!followed) + break; + res = 1; + } + return res; +} + static inline int simple_positive(struct dentry *dentry) { return dentry->d_inode && !d_unhashed(dentry); diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 500425e..feb6ac4 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -56,12 +56,9 @@ static int autofs4_check_mount(struct vfsmount *mnt, struct dentry *dentry) mntget(mnt); dget(dentry); - if (!follow_down(&mnt, &dentry)) + if (!autofs4_follow_mount(&mnt, &dentry)) goto done; - while (d_mountpoint(dentry) && follow_down(&mnt, &dentry)) - ; - /* This is an autofs submount, we can't expire it */ if (is_autofs4_dentry(dentry)) goto done; diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 3765c04..e137acf 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -205,7 +205,11 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) struct vfsmount *fp_mnt = mntget(mnt); struct dentry *fp_dentry = dget(dentry); - while (follow_down(&fp_mnt, &fp_dentry) && d_mountpoint(fp_dentry)); + if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) { + dput(fp_dentry); + mntput(fp_mnt); + return -ENOENT; + } fp = dentry_open(fp_dentry, fp_mnt, file->f_flags); status = PTR_ERR(fp); -- cgit v0.10.2 From cc9acc885819696c0ed00f4f0f0cda0c7583f116 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Tue, 21 Jun 2005 17:16:39 -0700 Subject: [PATCH] autofs4: post expire race fix At the tail end of an expire it's possible for a process to enter autofs4_wait, with a waitq type of NFY_NONE but find that the expire is finished. In this cause autofs4_wait will try to create a new wait but not notify the daemon leading to a hang. As the wait type is meant to delay mount requests from revalidate or lookup during an expire and the expire is done all we need to do is check if the dentry is a mountpoint. If it's not then we're done. Signed-off-by: Ian Kent Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 5a40d36..fa2348d 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -191,6 +191,13 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, } if ( !wq ) { + /* Can't wait for an expire if there's no mount */ + if (notify == NFY_NONE && !d_mountpoint(dentry)) { + kfree(name); + up(&sbi->wq_sem); + return -ENOENT; + } + /* Create a new wait queue */ wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); if ( !wq ) { -- cgit v0.10.2 From 1684b2bba6972749bc9acee57585acd6c78050b2 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Tue, 21 Jun 2005 17:16:41 -0700 Subject: [PATCH] autofs4: bad lookup fix For browsable autofs maps, a mount request that arrives at the same time an expire is happening can fail to perform the needed mount. This happens becuase the directory exists and so the revalidate succeeds when we need it to fail so that lookup is called on the same dentry to do the mount. Instead lookup is called on the next path component which should be whithin the mount, but the parent isn't mounted. The solution is to allow the revalidate to continue and perform the mount as no directory creation (at mount time) is needed for browsable mount entries. Signed-off-by: Ian Kent Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index e137acf..2a771ec 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -306,7 +306,14 @@ static int try_to_fill_dentry(struct dentry *dentry, DPRINTK("expire done status=%d", status); - return 0; + /* + * If the directory still exists the mount request must + * continue otherwise it can't be followed at the right + * time during the walk. + */ + status = d_invalidate(dentry); + if (status != -EBUSY) + return 0; } DPRINTK("dentry=%p %.*s ino=%p", -- cgit v0.10.2 From 8a96619145840c6eb50d85759f72d9337db411f7 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Tue, 21 Jun 2005 17:16:41 -0700 Subject: [PATCH] autofs4: subversion bump to identify these changes Signed-off-by: Ian Kent Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h index a1657fb..9343c89 100644 --- a/include/linux/auto_fs4.h +++ b/include/linux/auto_fs4.h @@ -23,7 +23,7 @@ #define AUTOFS_MIN_PROTO_VERSION 3 #define AUTOFS_MAX_PROTO_VERSION 4 -#define AUTOFS_PROTO_SUBVERSION 6 +#define AUTOFS_PROTO_SUBVERSION 7 /* Mask for expire behaviour */ #define AUTOFS_EXP_IMMEDIATE 1 -- cgit v0.10.2 From 1d372116383f79e42a3eb010c7d6ec3dd28767b3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:42 -0700 Subject: [PATCH] rock: lindent it Trying to turn rock.c into something which humans can read so we can fix some bugs. Start out by feeding it through scripts/Lindent. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 089e79c..bbc348f 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -20,8 +20,7 @@ * returns a symbolic link name, and a fourth one returns the extent number * for the file. */ -#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ - +#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ /* This is a way of ensuring that we have something in the system use fields that is compatible with Rock Ridge */ @@ -54,7 +53,7 @@ CHR+=ISOFS_SB(inode->i_sb)->s_rock_offset; \ if (LEN<0) LEN=0; \ } \ -} +} #define MAYBE_CONTINUE(LABEL,DEV) \ {if (buffer) { kfree(buffer); buffer = NULL; } \ @@ -85,280 +84,348 @@ }} /* return length of name field; 0: not found, -1: to be ignored */ -int get_rock_ridge_filename(struct iso_directory_record * de, - char * retname, struct inode * inode) +int get_rock_ridge_filename(struct iso_directory_record *de, + char *retname, struct inode *inode) { - int len; - unsigned char * chr; - CONTINUE_DECLS; - int retnamlen = 0, truncate=0; - - if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; - *retname = 0; - - SETUP_ROCK_RIDGE(de, chr, len); - repeat: - { - struct rock_ridge * rr; - int sig; - - while (len > 2){ /* There may be one byte for padding somewhere */ - rr = (struct rock_ridge *) chr; - if (rr->len < 3) goto out; /* Something got screwed up here */ - sig = isonum_721(chr); - chr += rr->len; - len -= rr->len; - if (len < 0) goto out; /* corrupted isofs */ - - switch(sig){ - case SIG('R','R'): - if((rr->u.RR.flags[0] & RR_NM) == 0) goto out; - break; - case SIG('S','P'): - CHECK_SP(goto out); - break; - case SIG('C','E'): - CHECK_CE; - break; - case SIG('N','M'): - if (truncate) break; - if (rr->len < 5) break; - /* - * If the flags are 2 or 4, this indicates '.' or '..'. - * We don't want to do anything with this, because it - * screws up the code that calls us. We don't really - * care anyways, since we can just use the non-RR - * name. - */ - if (rr->u.NM.flags & 6) { - break; - } + int len; + unsigned char *chr; + CONTINUE_DECLS; + int retnamlen = 0, truncate = 0; - if (rr->u.NM.flags & ~1) { - printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags); - break; - } - if((strlen(retname) + rr->len - 5) >= 254) { - truncate = 1; - break; + if (!ISOFS_SB(inode->i_sb)->s_rock) + return 0; + *retname = 0; + + SETUP_ROCK_RIDGE(de, chr, len); + repeat: + { + struct rock_ridge *rr; + int sig; + + while (len > 2) { /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *)chr; + if (rr->len < 3) + goto out; /* Something got screwed up here */ + sig = isonum_721(chr); + chr += rr->len; + len -= rr->len; + if (len < 0) + goto out; /* corrupted isofs */ + + switch (sig) { + case SIG('R', 'R'): + if ((rr->u.RR.flags[0] & RR_NM) == 0) + goto out; + break; + case SIG('S', 'P'): + CHECK_SP(goto out); + break; + case SIG('C', 'E'): + CHECK_CE; + break; + case SIG('N', 'M'): + if (truncate) + break; + if (rr->len < 5) + break; + /* + * If the flags are 2 or 4, this indicates '.' or '..'. + * We don't want to do anything with this, because it + * screws up the code that calls us. We don't really + * care anyways, since we can just use the non-RR + * name. + */ + if (rr->u.NM.flags & 6) { + break; + } + + if (rr->u.NM.flags & ~1) { + printk + ("Unsupported NM flag settings (%d)\n", + rr->u.NM.flags); + break; + } + if ((strlen(retname) + rr->len - 5) >= 254) { + truncate = 1; + break; + } + strncat(retname, rr->u.NM.name, rr->len - 5); + retnamlen += rr->len - 5; + break; + case SIG('R', 'E'): + if (buffer) + kfree(buffer); + return -1; + default: + break; + } + } } - strncat(retname, rr->u.NM.name, rr->len - 5); - retnamlen += rr->len - 5; - break; - case SIG('R','E'): - if (buffer) kfree(buffer); - return -1; - default: - break; - } - } - } - MAYBE_CONTINUE(repeat,inode); - if (buffer) kfree(buffer); - return retnamlen; /* If 0, this file did not have a NM field */ - out: - if(buffer) kfree(buffer); - return 0; + MAYBE_CONTINUE(repeat, inode); + if (buffer) + kfree(buffer); + return retnamlen; /* If 0, this file did not have a NM field */ + out: + if (buffer) + kfree(buffer); + return 0; } static int parse_rock_ridge_inode_internal(struct iso_directory_record *de, struct inode *inode, int regard_xa) { - int len; - unsigned char * chr; - int symlink_len = 0; - CONTINUE_DECLS; - - if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; - - SETUP_ROCK_RIDGE(de, chr, len); - if (regard_xa) - { - chr+=14; - len-=14; - if (len<0) len=0; - } - - repeat: - { - int cnt, sig; - struct inode * reloc; - struct rock_ridge * rr; - int rootflag; - - while (len > 2){ /* There may be one byte for padding somewhere */ - rr = (struct rock_ridge *) chr; - if (rr->len < 3) goto out; /* Something got screwed up here */ - sig = isonum_721(chr); - chr += rr->len; - len -= rr->len; - if (len < 0) goto out; /* corrupted isofs */ - - switch(sig){ + int len; + unsigned char *chr; + int symlink_len = 0; + CONTINUE_DECLS; + + if (!ISOFS_SB(inode->i_sb)->s_rock) + return 0; + + SETUP_ROCK_RIDGE(de, chr, len); + if (regard_xa) { + chr += 14; + len -= 14; + if (len < 0) + len = 0; + } + + repeat: + { + int cnt, sig; + struct inode *reloc; + struct rock_ridge *rr; + int rootflag; + + while (len > 2) { /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *)chr; + if (rr->len < 3) + goto out; /* Something got screwed up here */ + sig = isonum_721(chr); + chr += rr->len; + len -= rr->len; + if (len < 0) + goto out; /* corrupted isofs */ + + switch (sig) { #ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ - case SIG('R','R'): - if((rr->u.RR.flags[0] & - (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out; - break; + case SIG('R', 'R'): + if ((rr->u.RR.flags[0] & + (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) + goto out; + break; #endif - case SIG('S','P'): - CHECK_SP(goto out); - break; - case SIG('C','E'): - CHECK_CE; - break; - case SIG('E','R'): - ISOFS_SB(inode->i_sb)->s_rock = 1; - printk(KERN_DEBUG "ISO 9660 Extensions: "); - { int p; - for(p=0;pu.ER.len_id;p++) printk("%c",rr->u.ER.data[p]); - } - printk("\n"); - break; - case SIG('P','X'): - inode->i_mode = isonum_733(rr->u.PX.mode); - inode->i_nlink = isonum_733(rr->u.PX.n_links); - inode->i_uid = isonum_733(rr->u.PX.uid); - inode->i_gid = isonum_733(rr->u.PX.gid); - break; - case SIG('P','N'): - { int high, low; - high = isonum_733(rr->u.PN.dev_high); - low = isonum_733(rr->u.PN.dev_low); - /* - * The Rock Ridge standard specifies that if sizeof(dev_t) <= 4, - * then the high field is unused, and the device number is completely - * stored in the low field. Some writers may ignore this subtlety, - * and as a result we test to see if the entire device number is - * stored in the low field, and use that. - */ - if((low & ~0xff) && high == 0) { - inode->i_rdev = MKDEV(low >> 8, low & 0xff); - } else { - inode->i_rdev = MKDEV(high, low); - } - } - break; - case SIG('T','F'): - /* Some RRIP writers incorrectly place ctime in the TF_CREATE field. - Try to handle this correctly for either case. */ - cnt = 0; /* Rock ridge never appears on a High Sierra disk */ - if(rr->u.TF.flags & TF_CREATE) { - inode->i_ctime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); - inode->i_ctime.tv_nsec = 0; - } - if(rr->u.TF.flags & TF_MODIFY) { - inode->i_mtime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); - inode->i_mtime.tv_nsec = 0; - } - if(rr->u.TF.flags & TF_ACCESS) { - inode->i_atime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); - inode->i_atime.tv_nsec = 0; - } - if(rr->u.TF.flags & TF_ATTRIBUTES) { - inode->i_ctime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); - inode->i_ctime.tv_nsec = 0; - } - break; - case SIG('S','L'): - {int slen; - struct SL_component * slp; - struct SL_component * oldslp; - slen = rr->len - 5; - slp = &rr->u.SL.link; - inode->i_size = symlink_len; - while (slen > 1){ - rootflag = 0; - switch(slp->flags &~1){ - case 0: - inode->i_size += slp->len; - break; - case 2: - inode->i_size += 1; - break; - case 4: - inode->i_size += 2; - break; - case 8: - rootflag = 1; - inode->i_size += 1; - break; - default: - printk("Symlink component flag not implemented\n"); - } - slen -= slp->len + 2; - oldslp = slp; - slp = (struct SL_component *) (((char *) slp) + slp->len + 2); - - if(slen < 2) { - if( ((rr->u.SL.flags & 1) != 0) - && ((oldslp->flags & 1) == 0) ) inode->i_size += 1; - break; - } - - /* - * If this component record isn't continued, then append a '/'. - */ - if (!rootflag && (oldslp->flags & 1) == 0) - inode->i_size += 1; - } - } - symlink_len = inode->i_size; - break; - case SIG('R','E'): - printk(KERN_WARNING "Attempt to read inode for relocated directory\n"); - goto out; - case SIG('C','L'): - ISOFS_I(inode)->i_first_extent = isonum_733(rr->u.CL.location); - reloc = isofs_iget(inode->i_sb, ISOFS_I(inode)->i_first_extent, 0); - if (!reloc) - goto out; - inode->i_mode = reloc->i_mode; - inode->i_nlink = reloc->i_nlink; - inode->i_uid = reloc->i_uid; - inode->i_gid = reloc->i_gid; - inode->i_rdev = reloc->i_rdev; - inode->i_size = reloc->i_size; - inode->i_blocks = reloc->i_blocks; - inode->i_atime = reloc->i_atime; - inode->i_ctime = reloc->i_ctime; - inode->i_mtime = reloc->i_mtime; - iput(reloc); - break; + case SIG('S', 'P'): + CHECK_SP(goto out); + break; + case SIG('C', 'E'): + CHECK_CE; + break; + case SIG('E', 'R'): + ISOFS_SB(inode->i_sb)->s_rock = 1; + printk(KERN_DEBUG "ISO 9660 Extensions: "); + { + int p; + for (p = 0; p < rr->u.ER.len_id; p++) + printk("%c", rr->u.ER.data[p]); + } + printk("\n"); + break; + case SIG('P', 'X'): + inode->i_mode = isonum_733(rr->u.PX.mode); + inode->i_nlink = isonum_733(rr->u.PX.n_links); + inode->i_uid = isonum_733(rr->u.PX.uid); + inode->i_gid = isonum_733(rr->u.PX.gid); + break; + case SIG('P', 'N'): + { + int high, low; + high = isonum_733(rr->u.PN.dev_high); + low = isonum_733(rr->u.PN.dev_low); + /* + * The Rock Ridge standard specifies that if sizeof(dev_t) <= 4, + * then the high field is unused, and the device number is completely + * stored in the low field. Some writers may ignore this subtlety, + * and as a result we test to see if the entire device number is + * stored in the low field, and use that. + */ + if ((low & ~0xff) && high == 0) { + inode->i_rdev = + MKDEV(low >> 8, low & 0xff); + } else { + inode->i_rdev = + MKDEV(high, low); + } + } + break; + case SIG('T', 'F'): + /* Some RRIP writers incorrectly place ctime in the TF_CREATE field. + Try to handle this correctly for either case. */ + cnt = 0; /* Rock ridge never appears on a High Sierra disk */ + if (rr->u.TF.flags & TF_CREATE) { + inode->i_ctime.tv_sec = + iso_date(rr->u.TF.times[cnt++].time, + 0); + inode->i_ctime.tv_nsec = 0; + } + if (rr->u.TF.flags & TF_MODIFY) { + inode->i_mtime.tv_sec = + iso_date(rr->u.TF.times[cnt++].time, + 0); + inode->i_mtime.tv_nsec = 0; + } + if (rr->u.TF.flags & TF_ACCESS) { + inode->i_atime.tv_sec = + iso_date(rr->u.TF.times[cnt++].time, + 0); + inode->i_atime.tv_nsec = 0; + } + if (rr->u.TF.flags & TF_ATTRIBUTES) { + inode->i_ctime.tv_sec = + iso_date(rr->u.TF.times[cnt++].time, + 0); + inode->i_ctime.tv_nsec = 0; + } + break; + case SIG('S', 'L'): + { + int slen; + struct SL_component *slp; + struct SL_component *oldslp; + slen = rr->len - 5; + slp = &rr->u.SL.link; + inode->i_size = symlink_len; + while (slen > 1) { + rootflag = 0; + switch (slp->flags & ~1) { + case 0: + inode->i_size += + slp->len; + break; + case 2: + inode->i_size += 1; + break; + case 4: + inode->i_size += 2; + break; + case 8: + rootflag = 1; + inode->i_size += 1; + break; + default: + printk + ("Symlink component flag not implemented\n"); + } + slen -= slp->len + 2; + oldslp = slp; + slp = + (struct SL_component + *)(((char *)slp) + + slp->len + 2); + + if (slen < 2) { + if (((rr->u.SL. + flags & 1) != 0) + && + ((oldslp-> + flags & 1) == 0)) + inode->i_size += + 1; + break; + } + + /* + * If this component record isn't continued, then append a '/'. + */ + if (!rootflag + && (oldslp->flags & 1) == 0) + inode->i_size += 1; + } + } + symlink_len = inode->i_size; + break; + case SIG('R', 'E'): + printk(KERN_WARNING + "Attempt to read inode for relocated directory\n"); + goto out; + case SIG('C', 'L'): + ISOFS_I(inode)->i_first_extent = + isonum_733(rr->u.CL.location); + reloc = + isofs_iget(inode->i_sb, + ISOFS_I(inode)->i_first_extent, + 0); + if (!reloc) + goto out; + inode->i_mode = reloc->i_mode; + inode->i_nlink = reloc->i_nlink; + inode->i_uid = reloc->i_uid; + inode->i_gid = reloc->i_gid; + inode->i_rdev = reloc->i_rdev; + inode->i_size = reloc->i_size; + inode->i_blocks = reloc->i_blocks; + inode->i_atime = reloc->i_atime; + inode->i_ctime = reloc->i_ctime; + inode->i_mtime = reloc->i_mtime; + iput(reloc); + break; #ifdef CONFIG_ZISOFS - case SIG('Z','F'): - if ( !ISOFS_SB(inode->i_sb)->s_nocompress ) { - int algo; - algo = isonum_721(rr->u.ZF.algorithm); - if ( algo == SIG('p','z') ) { - int block_shift = isonum_711(&rr->u.ZF.parms[1]); - if ( block_shift < PAGE_CACHE_SHIFT || block_shift > 17 ) { - printk(KERN_WARNING "isofs: Can't handle ZF block size of 2^%d\n", block_shift); - } else { - /* Note: we don't change i_blocks here */ - ISOFS_I(inode)->i_file_format = isofs_file_compressed; - /* Parameters to compression algorithm (header size, block size) */ - ISOFS_I(inode)->i_format_parm[0] = isonum_711(&rr->u.ZF.parms[0]); - ISOFS_I(inode)->i_format_parm[1] = isonum_711(&rr->u.ZF.parms[1]); - inode->i_size = isonum_733(rr->u.ZF.real_size); - } - } else { - printk(KERN_WARNING "isofs: Unknown ZF compression algorithm: %c%c\n", - rr->u.ZF.algorithm[0], rr->u.ZF.algorithm[1]); - } - } - break; + case SIG('Z', 'F'): + if (!ISOFS_SB(inode->i_sb)->s_nocompress) { + int algo; + algo = isonum_721(rr->u.ZF.algorithm); + if (algo == SIG('p', 'z')) { + int block_shift = + isonum_711(&rr->u.ZF. + parms[1]); + if (block_shift < + PAGE_CACHE_SHIFT + || block_shift > 17) { + printk(KERN_WARNING + "isofs: Can't handle ZF block size of 2^%d\n", + block_shift); + } else { + /* Note: we don't change i_blocks here */ + ISOFS_I(inode)-> + i_file_format = + isofs_file_compressed; + /* Parameters to compression algorithm (header size, block size) */ + ISOFS_I(inode)-> + i_format_parm[0] = + isonum_711(&rr->u. + ZF. + parms + [0]); + ISOFS_I(inode)-> + i_format_parm[1] = + isonum_711(&rr->u. + ZF. + parms + [1]); + inode->i_size = + isonum_733(rr->u.ZF. + real_size); + } + } else { + printk(KERN_WARNING + "isofs: Unknown ZF compression algorithm: %c%c\n", + rr->u.ZF.algorithm[0], + rr->u.ZF.algorithm[1]); + } + } + break; #endif - default: - break; - } - } - } - MAYBE_CONTINUE(repeat,inode); - out: - if(buffer) kfree(buffer); - return 0; + default: + break; + } + } + } + MAYBE_CONTINUE(repeat, inode); + out: + if (buffer) + kfree(buffer); + return 0; } static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) @@ -376,32 +443,32 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) if (slp->len > plimit - rpnt) return NULL; memcpy(rpnt, slp->text, slp->len); - rpnt+=slp->len; + rpnt += slp->len; break; case 2: if (rpnt >= plimit) return NULL; - *rpnt++='.'; + *rpnt++ = '.'; break; case 4: if (2 > plimit - rpnt) return NULL; - *rpnt++='.'; - *rpnt++='.'; + *rpnt++ = '.'; + *rpnt++ = '.'; break; case 8: if (rpnt >= plimit) return NULL; rootflag = 1; - *rpnt++='/'; + *rpnt++ = '/'; break; default: printk("Symlink component flag not implemented (%d)\n", - slp->flags); + slp->flags); } slen -= slp->len + 2; oldslp = slp; - slp = (struct SL_component *) ((char *) slp + slp->len + 2); + slp = (struct SL_component *)((char *)slp + slp->len + 2); if (slen < 2) { /* @@ -412,7 +479,7 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) !(oldslp->flags & 1)) { if (rpnt >= plimit) return NULL; - *rpnt++='/'; + *rpnt++ = '/'; } break; } @@ -423,24 +490,22 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) if (!rootflag && !(oldslp->flags & 1)) { if (rpnt >= plimit) return NULL; - *rpnt++='/'; + *rpnt++ = '/'; } } return rpnt; } -int parse_rock_ridge_inode(struct iso_directory_record * de, - struct inode * inode) +int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode) { - int result=parse_rock_ridge_inode_internal(de,inode,0); - /* if rockridge flag was reset and we didn't look for attributes - * behind eventual XA attributes, have a look there */ - if ((ISOFS_SB(inode->i_sb)->s_rock_offset==-1) - &&(ISOFS_SB(inode->i_sb)->s_rock==2)) - { - result=parse_rock_ridge_inode_internal(de,inode,14); - } - return result; + int result = parse_rock_ridge_inode_internal(de, inode, 0); + /* if rockridge flag was reset and we didn't look for attributes + * behind eventual XA attributes, have a look there */ + if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1) + && (ISOFS_SB(inode->i_sb)->s_rock == 2)) { + result = parse_rock_ridge_inode_internal(de, inode, 14); + } + return result; } /* readpage() for symlinks: reads symlink contents into the page and either @@ -449,7 +514,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, static int rock_ridge_symlink_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; - struct iso_inode_info *ei = ISOFS_I(inode); + struct iso_inode_info *ei = ISOFS_I(inode); char *link = kmap(page); unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); struct buffer_head *bh; @@ -472,10 +537,10 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) if (!bh) goto out_noread; - offset = ei->i_iget5_offset; - pnt = (unsigned char *) bh->b_data + offset; + offset = ei->i_iget5_offset; + pnt = (unsigned char *)bh->b_data + offset; - raw_inode = (struct iso_directory_record *) pnt; + raw_inode = (struct iso_directory_record *)pnt; /* * If we go past the end of the buffer, there is some sort of error. @@ -489,8 +554,8 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) SETUP_ROCK_RIDGE(raw_inode, chr, len); repeat: - while (len > 2) { /* There may be one byte for padding somewhere */ - rr = (struct rock_ridge *) chr; + while (len > 2) { /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *)chr; if (rr->len < 3) goto out; /* Something got screwed up here */ sig = isonum_721(chr); @@ -555,5 +620,5 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) } struct address_space_operations isofs_symlink_aops = { - .readpage = rock_ridge_symlink_readpage + .readpage = rock_ridge_symlink_readpage }; -- cgit v0.10.2 From 7fa393a1d3d9485e428a3c74b5599190c14b13db Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:43 -0700 Subject: [PATCH] rock: manual tidies Fix stuff which Lindent got wrong, rework a few deeply-nested blocks. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index bbc348f..e981c04 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -90,82 +90,78 @@ int get_rock_ridge_filename(struct iso_directory_record *de, int len; unsigned char *chr; CONTINUE_DECLS; - int retnamlen = 0, truncate = 0; + struct rock_ridge *rr; + int sig; + int retnamlen = 0; + int truncate = 0; if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; *retname = 0; SETUP_ROCK_RIDGE(de, chr, len); - repeat: - { - struct rock_ridge *rr; - int sig; - - while (len > 2) { /* There may be one byte for padding somewhere */ - rr = (struct rock_ridge *)chr; - if (rr->len < 3) - goto out; /* Something got screwed up here */ - sig = isonum_721(chr); - chr += rr->len; - len -= rr->len; - if (len < 0) - goto out; /* corrupted isofs */ - - switch (sig) { - case SIG('R', 'R'): - if ((rr->u.RR.flags[0] & RR_NM) == 0) - goto out; +repeat: + + while (len > 2) { /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *)chr; + if (rr->len < 3) + goto out; /* Something got screwed up here */ + sig = isonum_721(chr); + chr += rr->len; + len -= rr->len; + if (len < 0) + goto out; /* corrupted isofs */ + + switch (sig) { + case SIG('R', 'R'): + if ((rr->u.RR.flags[0] & RR_NM) == 0) + goto out; + break; + case SIG('S', 'P'): + CHECK_SP(goto out); + break; + case SIG('C', 'E'): + CHECK_CE; + break; + case SIG('N', 'M'): + if (truncate) break; - case SIG('S', 'P'): - CHECK_SP(goto out); + if (rr->len < 5) break; - case SIG('C', 'E'): - CHECK_CE; + /* + * If the flags are 2 or 4, this indicates '.' or '..'. + * We don't want to do anything with this, because it + * screws up the code that calls us. We don't really + * care anyways, since we can just use the non-RR + * name. + */ + if (rr->u.NM.flags & 6) break; - case SIG('N', 'M'): - if (truncate) - break; - if (rr->len < 5) - break; - /* - * If the flags are 2 or 4, this indicates '.' or '..'. - * We don't want to do anything with this, because it - * screws up the code that calls us. We don't really - * care anyways, since we can just use the non-RR - * name. - */ - if (rr->u.NM.flags & 6) { - break; - } - if (rr->u.NM.flags & ~1) { - printk - ("Unsupported NM flag settings (%d)\n", - rr->u.NM.flags); - break; - } - if ((strlen(retname) + rr->len - 5) >= 254) { - truncate = 1; - break; - } - strncat(retname, rr->u.NM.name, rr->len - 5); - retnamlen += rr->len - 5; + if (rr->u.NM.flags & ~1) { + printk("Unsupported NM flag settings (%d)\n", + rr->u.NM.flags); break; - case SIG('R', 'E'): - if (buffer) - kfree(buffer); - return -1; - default: + } + if ((strlen(retname) + rr->len - 5) >= 254) { + truncate = 1; break; } + strncat(retname, rr->u.NM.name, rr->len - 5); + retnamlen += rr->len - 5; + break; + case SIG('R', 'E'): + if (buffer) + kfree(buffer); + return -1; + default: + break; } } MAYBE_CONTINUE(repeat, inode); - if (buffer) - kfree(buffer); + kfree(buffer); return retnamlen; /* If 0, this file did not have a NM field */ - out: +out: if (buffer) kfree(buffer); return 0; @@ -178,6 +174,11 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, int len; unsigned char *chr; int symlink_len = 0; + int cnt, sig; + struct inode *reloc; + struct rock_ridge *rr; + int rootflag; + CONTINUE_DECLS; if (!ISOFS_SB(inode->i_sb)->s_rock) @@ -191,238 +192,237 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, len = 0; } - repeat: - { - int cnt, sig; - struct inode *reloc; - struct rock_ridge *rr; - int rootflag; - - while (len > 2) { /* There may be one byte for padding somewhere */ - rr = (struct rock_ridge *)chr; - if (rr->len < 3) - goto out; /* Something got screwed up here */ - sig = isonum_721(chr); - chr += rr->len; - len -= rr->len; - if (len < 0) - goto out; /* corrupted isofs */ - - switch (sig) { +repeat: + while (len > 2) { /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *)chr; + if (rr->len < 3) + goto out; /* Something got screwed up here */ + sig = isonum_721(chr); + chr += rr->len; + len -= rr->len; + if (len < 0) + goto out; /* corrupted isofs */ + + switch (sig) { #ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ - case SIG('R', 'R'): - if ((rr->u.RR.flags[0] & - (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) - goto out; - break; + case SIG('R', 'R'): + if ((rr->u.RR.flags[0] & + (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) + goto out; + break; #endif - case SIG('S', 'P'): - CHECK_SP(goto out); - break; - case SIG('C', 'E'): - CHECK_CE; - break; - case SIG('E', 'R'): - ISOFS_SB(inode->i_sb)->s_rock = 1; - printk(KERN_DEBUG "ISO 9660 Extensions: "); - { - int p; - for (p = 0; p < rr->u.ER.len_id; p++) - printk("%c", rr->u.ER.data[p]); + case SIG('S', 'P'): + CHECK_SP(goto out); + break; + case SIG('C', 'E'): + CHECK_CE; + break; + case SIG('E', 'R'): + ISOFS_SB(inode->i_sb)->s_rock = 1; + printk(KERN_DEBUG "ISO 9660 Extensions: "); + { + int p; + for (p = 0; p < rr->u.ER.len_id; p++) + printk("%c", rr->u.ER.data[p]); + } + printk("\n"); + break; + case SIG('P', 'X'): + inode->i_mode = isonum_733(rr->u.PX.mode); + inode->i_nlink = isonum_733(rr->u.PX.n_links); + inode->i_uid = isonum_733(rr->u.PX.uid); + inode->i_gid = isonum_733(rr->u.PX.gid); + break; + case SIG('P', 'N'): + { + int high, low; + high = isonum_733(rr->u.PN.dev_high); + low = isonum_733(rr->u.PN.dev_low); + /* + * The Rock Ridge standard specifies that if + * sizeof(dev_t) <= 4, then the high field is + * unused, and the device number is completely + * stored in the low field. Some writers may + * ignore this subtlety, + * and as a result we test to see if the entire + * device number is + * stored in the low field, and use that. + */ + if ((low & ~0xff) && high == 0) { + inode->i_rdev = + MKDEV(low >> 8, low & 0xff); + } else { + inode->i_rdev = + MKDEV(high, low); } - printk("\n"); - break; - case SIG('P', 'X'): - inode->i_mode = isonum_733(rr->u.PX.mode); - inode->i_nlink = isonum_733(rr->u.PX.n_links); - inode->i_uid = isonum_733(rr->u.PX.uid); - inode->i_gid = isonum_733(rr->u.PX.gid); - break; - case SIG('P', 'N'): - { - int high, low; - high = isonum_733(rr->u.PN.dev_high); - low = isonum_733(rr->u.PN.dev_low); - /* - * The Rock Ridge standard specifies that if sizeof(dev_t) <= 4, - * then the high field is unused, and the device number is completely - * stored in the low field. Some writers may ignore this subtlety, - * and as a result we test to see if the entire device number is - * stored in the low field, and use that. - */ - if ((low & ~0xff) && high == 0) { - inode->i_rdev = - MKDEV(low >> 8, low & 0xff); - } else { - inode->i_rdev = - MKDEV(high, low); + } + break; + case SIG('T', 'F'): + /* + * Some RRIP writers incorrectly place ctime in the + * TF_CREATE field. Try to handle this correctly for + * either case. + */ + /* Rock ridge never appears on a High Sierra disk */ + cnt = 0; + if (rr->u.TF.flags & TF_CREATE) { + inode->i_ctime.tv_sec = + iso_date(rr->u.TF.times[cnt++].time, + 0); + inode->i_ctime.tv_nsec = 0; + } + if (rr->u.TF.flags & TF_MODIFY) { + inode->i_mtime.tv_sec = + iso_date(rr->u.TF.times[cnt++].time, + 0); + inode->i_mtime.tv_nsec = 0; + } + if (rr->u.TF.flags & TF_ACCESS) { + inode->i_atime.tv_sec = + iso_date(rr->u.TF.times[cnt++].time, + 0); + inode->i_atime.tv_nsec = 0; + } + if (rr->u.TF.flags & TF_ATTRIBUTES) { + inode->i_ctime.tv_sec = + iso_date(rr->u.TF.times[cnt++].time, + 0); + inode->i_ctime.tv_nsec = 0; + } + break; + case SIG('S', 'L'): + { + int slen; + struct SL_component *slp; + struct SL_component *oldslp; + slen = rr->len - 5; + slp = &rr->u.SL.link; + inode->i_size = symlink_len; + while (slen > 1) { + rootflag = 0; + switch (slp->flags & ~1) { + case 0: + inode->i_size += + slp->len; + break; + case 2: + inode->i_size += 1; + break; + case 4: + inode->i_size += 2; + break; + case 8: + rootflag = 1; + inode->i_size += 1; + break; + default: + printk("Symlink component flag " + "not implemented\n"); } - } - break; - case SIG('T', 'F'): - /* Some RRIP writers incorrectly place ctime in the TF_CREATE field. - Try to handle this correctly for either case. */ - cnt = 0; /* Rock ridge never appears on a High Sierra disk */ - if (rr->u.TF.flags & TF_CREATE) { - inode->i_ctime.tv_sec = - iso_date(rr->u.TF.times[cnt++].time, - 0); - inode->i_ctime.tv_nsec = 0; - } - if (rr->u.TF.flags & TF_MODIFY) { - inode->i_mtime.tv_sec = - iso_date(rr->u.TF.times[cnt++].time, - 0); - inode->i_mtime.tv_nsec = 0; - } - if (rr->u.TF.flags & TF_ACCESS) { - inode->i_atime.tv_sec = - iso_date(rr->u.TF.times[cnt++].time, - 0); - inode->i_atime.tv_nsec = 0; - } - if (rr->u.TF.flags & TF_ATTRIBUTES) { - inode->i_ctime.tv_sec = - iso_date(rr->u.TF.times[cnt++].time, - 0); - inode->i_ctime.tv_nsec = 0; - } - break; - case SIG('S', 'L'): - { - int slen; - struct SL_component *slp; - struct SL_component *oldslp; - slen = rr->len - 5; - slp = &rr->u.SL.link; - inode->i_size = symlink_len; - while (slen > 1) { - rootflag = 0; - switch (slp->flags & ~1) { - case 0: + slen -= slp->len + 2; + oldslp = slp; + slp = (struct SL_component *) + (((char *)slp) + slp->len + 2); + + if (slen < 2) { + if (((rr->u.SL. + flags & 1) != 0) + && + ((oldslp-> + flags & 1) == 0)) inode->i_size += - slp->len; - break; - case 2: - inode->i_size += 1; - break; - case 4: - inode->i_size += 2; - break; - case 8: - rootflag = 1; - inode->i_size += 1; - break; - default: - printk - ("Symlink component flag not implemented\n"); - } - slen -= slp->len + 2; - oldslp = slp; - slp = - (struct SL_component - *)(((char *)slp) + - slp->len + 2); - - if (slen < 2) { - if (((rr->u.SL. - flags & 1) != 0) - && - ((oldslp-> - flags & 1) == 0)) - inode->i_size += - 1; - break; - } - - /* - * If this component record isn't continued, then append a '/'. - */ - if (!rootflag - && (oldslp->flags & 1) == 0) - inode->i_size += 1; + 1; + break; } + + /* + * If this component record isn't + * continued, then append a '/'. + */ + if (!rootflag + && (oldslp->flags & 1) == 0) + inode->i_size += 1; } - symlink_len = inode->i_size; - break; - case SIG('R', 'E'): - printk(KERN_WARNING - "Attempt to read inode for relocated directory\n"); + } + symlink_len = inode->i_size; + break; + case SIG('R', 'E'): + printk(KERN_WARNING "Attempt to read inode for " + "relocated directory\n"); + goto out; + case SIG('C', 'L'): + ISOFS_I(inode)->i_first_extent = + isonum_733(rr->u.CL.location); + reloc = + isofs_iget(inode->i_sb, + ISOFS_I(inode)->i_first_extent, + 0); + if (!reloc) goto out; - case SIG('C', 'L'): - ISOFS_I(inode)->i_first_extent = - isonum_733(rr->u.CL.location); - reloc = - isofs_iget(inode->i_sb, - ISOFS_I(inode)->i_first_extent, - 0); - if (!reloc) - goto out; - inode->i_mode = reloc->i_mode; - inode->i_nlink = reloc->i_nlink; - inode->i_uid = reloc->i_uid; - inode->i_gid = reloc->i_gid; - inode->i_rdev = reloc->i_rdev; - inode->i_size = reloc->i_size; - inode->i_blocks = reloc->i_blocks; - inode->i_atime = reloc->i_atime; - inode->i_ctime = reloc->i_ctime; - inode->i_mtime = reloc->i_mtime; - iput(reloc); - break; + inode->i_mode = reloc->i_mode; + inode->i_nlink = reloc->i_nlink; + inode->i_uid = reloc->i_uid; + inode->i_gid = reloc->i_gid; + inode->i_rdev = reloc->i_rdev; + inode->i_size = reloc->i_size; + inode->i_blocks = reloc->i_blocks; + inode->i_atime = reloc->i_atime; + inode->i_ctime = reloc->i_ctime; + inode->i_mtime = reloc->i_mtime; + iput(reloc); + break; #ifdef CONFIG_ZISOFS - case SIG('Z', 'F'): - if (!ISOFS_SB(inode->i_sb)->s_nocompress) { - int algo; - algo = isonum_721(rr->u.ZF.algorithm); - if (algo == SIG('p', 'z')) { - int block_shift = - isonum_711(&rr->u.ZF. - parms[1]); - if (block_shift < - PAGE_CACHE_SHIFT - || block_shift > 17) { - printk(KERN_WARNING - "isofs: Can't handle ZF block size of 2^%d\n", - block_shift); - } else { - /* Note: we don't change i_blocks here */ - ISOFS_I(inode)-> - i_file_format = - isofs_file_compressed; - /* Parameters to compression algorithm (header size, block size) */ - ISOFS_I(inode)-> - i_format_parm[0] = - isonum_711(&rr->u. - ZF. - parms - [0]); - ISOFS_I(inode)-> - i_format_parm[1] = - isonum_711(&rr->u. - ZF. - parms - [1]); - inode->i_size = - isonum_733(rr->u.ZF. - real_size); - } - } else { - printk(KERN_WARNING - "isofs: Unknown ZF compression algorithm: %c%c\n", - rr->u.ZF.algorithm[0], - rr->u.ZF.algorithm[1]); - } - } - break; -#endif - default: + case SIG('Z', 'F'): { + int algo; + + if (ISOFS_SB(inode->i_sb)->s_nocompress) break; + algo = isonum_721(rr->u.ZF.algorithm); + if (algo == SIG('p', 'z')) { + int block_shift = + isonum_711(&rr->u.ZF.parms[1]); + if (block_shift < PAGE_CACHE_SHIFT + || block_shift > 17) { + printk(KERN_WARNING "isofs: " + "Can't handle ZF block " + "size of 2^%d\n", + block_shift); + } else { + /* + * Note: we don't change + * i_blocks here + */ + ISOFS_I(inode)->i_file_format = + isofs_file_compressed; + /* + * Parameters to compression + * algorithm (header size, + * block size) + */ + ISOFS_I(inode)->i_format_parm[0] = + isonum_711(&rr->u.ZF.parms[0]); + ISOFS_I(inode)->i_format_parm[1] = + isonum_711(&rr->u.ZF.parms[1]); + inode->i_size = + isonum_733(rr->u.ZF. + real_size); + } + } else { + printk(KERN_WARNING + "isofs: Unknown ZF compression " + "algorithm: %c%c\n", + rr->u.ZF.algorithm[0], + rr->u.ZF.algorithm[1]); } + break; + } +#endif + default: + break; } } MAYBE_CONTINUE(repeat, inode); - out: +out: if (buffer) kfree(buffer); return 0; @@ -553,8 +553,8 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) SETUP_ROCK_RIDGE(raw_inode, chr, len); - repeat: - while (len > 2) { /* There may be one byte for padding somewhere */ +repeat: + while (len > 2) { /* There may be one byte for padding somewhere */ rr = (struct rock_ridge *)chr; if (rr->len < 3) goto out; /* Something got screwed up here */ @@ -586,8 +586,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) } } MAYBE_CONTINUE(repeat, inode); - if (buffer) - kfree(buffer); + kfree(buffer); if (rpnt == link) goto fail; @@ -600,19 +599,19 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) return 0; /* error exit from macro */ - out: +out: if (buffer) kfree(buffer); goto fail; - out_noread: +out_noread: printk("unable to read i-node block"); goto fail; - out_bad_span: +out_bad_span: printk("symlink spans iso9660 blocks\n"); - fail: +fail: brelse(bh); unlock_kernel(); - error: +error: SetPageError(page); kunmap(page); unlock_page(page); -- cgit v0.10.2 From 12121714fbf36023d5892034d0c97df54a451543 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:44 -0700 Subject: [PATCH] rock: remove CHECK_SP Remove the CHECK_SP macro. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index e981c04..8497c6b 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -22,12 +22,21 @@ #define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ -/* This is a way of ensuring that we have something in the system - use fields that is compatible with Rock Ridge */ -#define CHECK_SP(FAIL) \ - if(rr->u.SP.magic[0] != 0xbe) FAIL; \ - if(rr->u.SP.magic[1] != 0xef) FAIL; \ - ISOFS_SB(inode->i_sb)->s_rock_offset=rr->u.SP.skip; +/* + * This is a way of ensuring that we have something in the system + * use fields that is compatible with Rock Ridge. Return zero on success. + */ + +static int check_sp(struct rock_ridge *rr, struct inode *inode) +{ + if (rr->u.SP.magic[0] != 0xbe) + return -1; + if (rr->u.SP.magic[1] != 0xef) + return -1; + ISOFS_SB(inode->i_sb)->s_rock_offset = rr->u.SP.skip; + return 0; +} + /* We define a series of macros because each function must do exactly the same thing in certain places. We use the macros to ensure that everything is done correctly */ @@ -118,7 +127,8 @@ repeat: goto out; break; case SIG('S', 'P'): - CHECK_SP(goto out); + if (check_sp(rr, inode)) + goto out; break; case SIG('C', 'E'): CHECK_CE; @@ -212,7 +222,8 @@ repeat: break; #endif case SIG('S', 'P'): - CHECK_SP(goto out); + if (check_sp(rr, inode)) + goto out; break; case SIG('C', 'E'): CHECK_CE; @@ -570,7 +581,8 @@ repeat: goto out; break; case SIG('S', 'P'): - CHECK_SP(goto out); + if (check_sp(rr, inode)) + goto out; break; case SIG('S', 'L'): rpnt = get_symlink_chunk(rpnt, rr, -- cgit v0.10.2 From a40ea8f22e59c038ffdf219251a67311b9f6e362 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:44 -0700 Subject: [PATCH] rock: remove CONTINUE_DECLS Remove the CONTINUE_DECLS macro. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 8497c6b..9f2aaa2 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -37,14 +37,6 @@ static int check_sp(struct rock_ridge *rr, struct inode *inode) return 0; } -/* We define a series of macros because each function must do exactly the - same thing in certain places. We use the macros to ensure that everything - is done correctly */ - -#define CONTINUE_DECLS \ - int cont_extent = 0, cont_offset = 0, cont_size = 0; \ - void *buffer = NULL - #define CHECK_CE \ {cont_extent = isonum_733(rr->u.CE.extent); \ cont_offset = isonum_733(rr->u.CE.offset); \ @@ -98,7 +90,10 @@ int get_rock_ridge_filename(struct iso_directory_record *de, { int len; unsigned char *chr; - CONTINUE_DECLS; + int cont_extent = 0; + int cont_offset = 0; + int cont_size = 0; + void *buffer = NULL; struct rock_ridge *rr; int sig; int retnamlen = 0; @@ -188,8 +183,10 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, struct inode *reloc; struct rock_ridge *rr; int rootflag; - - CONTINUE_DECLS; + int cont_extent = 0; + int cont_offset = 0; + int cont_size = 0; + void *buffer = NULL; if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; @@ -532,7 +529,10 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) char *rpnt = link; unsigned char *pnt; struct iso_directory_record *raw_inode; - CONTINUE_DECLS; + int cont_extent = 0; + int cont_offset = 0; + int cont_size = 0; + void *buffer = NULL; unsigned long block, offset; int sig; int len; -- cgit v0.10.2 From 04f7aa9c7dc615c690cede9a80c83625ad2efef7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:45 -0700 Subject: [PATCH] rock: remove CHECK_CE Remove the CHECK_CE macro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 9f2aaa2..283e921 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -37,11 +37,6 @@ static int check_sp(struct rock_ridge *rr, struct inode *inode) return 0; } -#define CHECK_CE \ - {cont_extent = isonum_733(rr->u.CE.extent); \ - cont_offset = isonum_733(rr->u.CE.offset); \ - cont_size = isonum_733(rr->u.CE.size);} - #define SETUP_ROCK_RIDGE(DE,CHR,LEN) \ {LEN= sizeof(struct iso_directory_record) + DE->name_len[0]; \ if(LEN & 1) LEN++; \ @@ -126,7 +121,9 @@ repeat: goto out; break; case SIG('C', 'E'): - CHECK_CE; + cont_extent = isonum_733(rr->u.CE.extent); + cont_offset = isonum_733(rr->u.CE.offset); + cont_size = isonum_733(rr->u.CE.size); break; case SIG('N', 'M'): if (truncate) @@ -223,7 +220,9 @@ repeat: goto out; break; case SIG('C', 'E'): - CHECK_CE; + cont_extent = isonum_733(rr->u.CE.extent); + cont_offset = isonum_733(rr->u.CE.offset); + cont_size = isonum_733(rr->u.CE.size); break; case SIG('E', 'R'): ISOFS_SB(inode->i_sb)->s_rock = 1; @@ -592,7 +591,9 @@ repeat: break; case SIG('C', 'E'): /* This tells is if there is a continuation record */ - CHECK_CE; + cont_extent = isonum_733(rr->u.CE.extent); + cont_offset = isonum_733(rr->u.CE.offset); + cont_size = isonum_733(rr->u.CE.size); default: break; } -- cgit v0.10.2 From 76ab07ebc3ca69e2f14ccbed0de3a9dda9adc6da Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:46 -0700 Subject: [PATCH] rock: remove SETUP_ROCK_RIDGE - Remove the SETUP_ROCK_RIDGE macro. - In rock_ridge_symlink_readpage(), rename raw_inode to raw_de. It points at a directory entry, not an inode. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 283e921..aafe356 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -37,18 +37,23 @@ static int check_sp(struct rock_ridge *rr, struct inode *inode) return 0; } -#define SETUP_ROCK_RIDGE(DE,CHR,LEN) \ - {LEN= sizeof(struct iso_directory_record) + DE->name_len[0]; \ - if(LEN & 1) LEN++; \ - CHR = ((unsigned char *) DE) + LEN; \ - LEN = *((unsigned char *) DE) - LEN; \ - if (LEN<0) LEN=0; \ - if (ISOFS_SB(inode->i_sb)->s_rock_offset!=-1) \ - { \ - LEN-=ISOFS_SB(inode->i_sb)->s_rock_offset; \ - CHR+=ISOFS_SB(inode->i_sb)->s_rock_offset; \ - if (LEN<0) LEN=0; \ - } \ +static void setup_rock_ridge(struct iso_directory_record *de, + struct inode *inode, unsigned char **chr, int *len) +{ + *len = sizeof(struct iso_directory_record) + de->name_len[0]; + if (*len & 1) + (*len)++; + *chr = (unsigned char *)de + *len; + *len = *((unsigned char *)de) - *len; + if (*len < 0) + *len = 0; + + if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) { + *len -= ISOFS_SB(inode->i_sb)->s_rock_offset; + *chr += ISOFS_SB(inode->i_sb)->s_rock_offset; + if (*len < 0) + *len = 0; + } } #define MAYBE_CONTINUE(LABEL,DEV) \ @@ -98,7 +103,7 @@ int get_rock_ridge_filename(struct iso_directory_record *de, return 0; *retname = 0; - SETUP_ROCK_RIDGE(de, chr, len); + setup_rock_ridge(de, inode, &chr, &len); repeat: while (len > 2) { /* There may be one byte for padding somewhere */ @@ -188,7 +193,7 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; - SETUP_ROCK_RIDGE(de, chr, len); + setup_rock_ridge(de, inode, &chr, &len); if (regard_xa) { chr += 14; len -= 14; @@ -527,7 +532,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) struct buffer_head *bh; char *rpnt = link; unsigned char *pnt; - struct iso_directory_record *raw_inode; + struct iso_directory_record *raw_de; int cont_extent = 0; int cont_offset = 0; int cont_size = 0; @@ -550,7 +555,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) offset = ei->i_iget5_offset; pnt = (unsigned char *)bh->b_data + offset; - raw_inode = (struct iso_directory_record *)pnt; + raw_de = (struct iso_directory_record *)pnt; /* * If we go past the end of the buffer, there is some sort of error. @@ -561,7 +566,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) /* Now test for possible Rock Ridge extensions which will override some of these numbers in the inode structure. */ - SETUP_ROCK_RIDGE(raw_inode, chr, len); + setup_rock_ridge(raw_de, inode, &chr, &len); repeat: while (len > 2) { /* There may be one byte for padding somewhere */ -- cgit v0.10.2 From ba40aaf04314ec5efd090e69518033fc55f450fa Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:46 -0700 Subject: [PATCH] rock: remove MAYBE_CONTINUE - remove the MAYBE_CONTINUE macro - kfree(NULL) is OK. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index aafe356..efefbcce 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -22,6 +22,16 @@ #define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ +struct rock_state { + void *buffer; + unsigned char *chr; + int len; + int cont_size; + int cont_extent; + int cont_offset; + struct inode *inode; +}; + /* * This is a way of ensuring that we have something in the system * use fields that is compatible with Rock Ridge. Return zero on success. @@ -38,82 +48,96 @@ static int check_sp(struct rock_ridge *rr, struct inode *inode) } static void setup_rock_ridge(struct iso_directory_record *de, - struct inode *inode, unsigned char **chr, int *len) + struct inode *inode, struct rock_state *rs) { - *len = sizeof(struct iso_directory_record) + de->name_len[0]; - if (*len & 1) - (*len)++; - *chr = (unsigned char *)de + *len; - *len = *((unsigned char *)de) - *len; - if (*len < 0) - *len = 0; + rs->len = sizeof(struct iso_directory_record) + de->name_len[0]; + if (rs->len & 1) + (rs->len)++; + rs->chr = (unsigned char *)de + rs->len; + rs->len = *((unsigned char *)de) - rs->len; + if (rs->len < 0) + rs->len = 0; if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) { - *len -= ISOFS_SB(inode->i_sb)->s_rock_offset; - *chr += ISOFS_SB(inode->i_sb)->s_rock_offset; - if (*len < 0) - *len = 0; + rs->len -= ISOFS_SB(inode->i_sb)->s_rock_offset; + rs->chr += ISOFS_SB(inode->i_sb)->s_rock_offset; + if (rs->len < 0) + rs->len = 0; } } -#define MAYBE_CONTINUE(LABEL,DEV) \ - {if (buffer) { kfree(buffer); buffer = NULL; } \ - if (cont_extent){ \ - int block, offset, offset1; \ - struct buffer_head * pbh; \ - buffer = kmalloc(cont_size,GFP_KERNEL); \ - if (!buffer) goto out; \ - block = cont_extent; \ - offset = cont_offset; \ - offset1 = 0; \ - pbh = sb_bread(DEV->i_sb, block); \ - if(pbh){ \ - if (offset > pbh->b_size || offset + cont_size > pbh->b_size){ \ - brelse(pbh); \ - goto out; \ - } \ - memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \ - brelse(pbh); \ - chr = (unsigned char *) buffer; \ - len = cont_size; \ - cont_extent = 0; \ - cont_size = 0; \ - cont_offset = 0; \ - goto LABEL; \ - } \ - printk("Unable to read rock-ridge attributes\n"); \ - }} +static void init_rock_state(struct rock_state *rs, struct inode *inode) +{ + memset(rs, 0, sizeof(*rs)); + rs->inode = inode; +} + +/* + * Returns 0 if the caller should continue scanning, 1 if the scan must end + * and -ve on error. + */ +static int rock_continue(struct rock_state *rs) +{ + int ret = 1; + + kfree(rs->buffer); + rs->buffer = NULL; + if (rs->cont_extent) { + struct buffer_head *bh; + + rs->buffer = kmalloc(rs->cont_size, GFP_KERNEL); + if (!rs->buffer) { + ret = -ENOMEM; + goto out; + } + ret = -EIO; + bh = sb_bread(rs->inode->i_sb, rs->cont_extent); + if (bh) { + memcpy(rs->buffer, bh->b_data + rs->cont_offset, + rs->cont_size); + put_bh(bh); + rs->chr = rs->buffer; + rs->len = rs->cont_size; + rs->cont_extent = 0; + rs->cont_size = 0; + rs->cont_offset = 0; + return 0; + } + printk("Unable to read rock-ridge attributes\n"); + } +out: + kfree(rs->buffer); + rs->buffer = NULL; + return ret; +} /* return length of name field; 0: not found, -1: to be ignored */ int get_rock_ridge_filename(struct iso_directory_record *de, char *retname, struct inode *inode) { - int len; - unsigned char *chr; - int cont_extent = 0; - int cont_offset = 0; - int cont_size = 0; - void *buffer = NULL; + struct rock_state rs; struct rock_ridge *rr; int sig; int retnamlen = 0; int truncate = 0; + int ret = 0; if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; *retname = 0; - setup_rock_ridge(de, inode, &chr, &len); + init_rock_state(&rs, inode); + setup_rock_ridge(de, inode, &rs); repeat: - while (len > 2) { /* There may be one byte for padding somewhere */ - rr = (struct rock_ridge *)chr; + while (rs.len > 2) { /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *)rs.chr; if (rr->len < 3) goto out; /* Something got screwed up here */ - sig = isonum_721(chr); - chr += rr->len; - len -= rr->len; - if (len < 0) + sig = isonum_721(rs.chr); + rs.chr += rr->len; + rs.len -= rr->len; + if (rs.len < 0) goto out; /* corrupted isofs */ switch (sig) { @@ -126,9 +150,9 @@ repeat: goto out; break; case SIG('C', 'E'): - cont_extent = isonum_733(rr->u.CE.extent); - cont_offset = isonum_733(rr->u.CE.offset); - cont_size = isonum_733(rr->u.CE.size); + rs.cont_extent = isonum_733(rr->u.CE.extent); + rs.cont_offset = isonum_733(rr->u.CE.offset); + rs.cont_size = isonum_733(rr->u.CE.size); break; case SIG('N', 'M'): if (truncate) @@ -158,58 +182,55 @@ repeat: retnamlen += rr->len - 5; break; case SIG('R', 'E'): - if (buffer) - kfree(buffer); + kfree(rs.buffer); return -1; default: break; } } - MAYBE_CONTINUE(repeat, inode); - kfree(buffer); - return retnamlen; /* If 0, this file did not have a NM field */ + ret = rock_continue(&rs); + if (ret == 0) + goto repeat; + if (ret == 1) + return retnamlen; /* If 0, this file did not have a NM field */ out: - if (buffer) - kfree(buffer); - return 0; + kfree(rs.buffer); + return ret; } static int parse_rock_ridge_inode_internal(struct iso_directory_record *de, struct inode *inode, int regard_xa) { - int len; - unsigned char *chr; int symlink_len = 0; int cnt, sig; struct inode *reloc; struct rock_ridge *rr; int rootflag; - int cont_extent = 0; - int cont_offset = 0; - int cont_size = 0; - void *buffer = NULL; + struct rock_state rs; + int ret = 0; if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; - setup_rock_ridge(de, inode, &chr, &len); + init_rock_state(&rs, inode); + setup_rock_ridge(de, inode, &rs); if (regard_xa) { - chr += 14; - len -= 14; - if (len < 0) - len = 0; + rs.chr += 14; + rs.len -= 14; + if (rs.len < 0) + rs.len = 0; } repeat: - while (len > 2) { /* There may be one byte for padding somewhere */ - rr = (struct rock_ridge *)chr; + while (rs.len > 2) { /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *)rs.chr; if (rr->len < 3) goto out; /* Something got screwed up here */ - sig = isonum_721(chr); - chr += rr->len; - len -= rr->len; - if (len < 0) + sig = isonum_721(rs.chr); + rs.chr += rr->len; + rs.len -= rr->len; + if (rs.len < 0) goto out; /* corrupted isofs */ switch (sig) { @@ -225,9 +246,9 @@ repeat: goto out; break; case SIG('C', 'E'): - cont_extent = isonum_733(rr->u.CE.extent); - cont_offset = isonum_733(rr->u.CE.offset); - cont_size = isonum_733(rr->u.CE.size); + rs.cont_extent = isonum_733(rr->u.CE.extent); + rs.cont_offset = isonum_733(rr->u.CE.offset); + rs.cont_size = isonum_733(rr->u.CE.size); break; case SIG('E', 'R'): ISOFS_SB(inode->i_sb)->s_rock = 1; @@ -433,11 +454,14 @@ repeat: break; } } - MAYBE_CONTINUE(repeat, inode); + ret = rock_continue(&rs); + if (ret == 0) + goto repeat; + if (ret == 1) + ret = 0; out: - if (buffer) - kfree(buffer); - return 0; + kfree(rs.buffer); + return ret; } static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) @@ -533,19 +557,16 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) char *rpnt = link; unsigned char *pnt; struct iso_directory_record *raw_de; - int cont_extent = 0; - int cont_offset = 0; - int cont_size = 0; - void *buffer = NULL; unsigned long block, offset; int sig; - int len; - unsigned char *chr; struct rock_ridge *rr; + struct rock_state rs; + int ret; if (!ISOFS_SB(inode->i_sb)->s_rock) goto error; + init_rock_state(&rs, inode); block = ei->i_iget5_block; lock_kernel(); bh = sb_bread(inode->i_sb, block); @@ -566,17 +587,17 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) /* Now test for possible Rock Ridge extensions which will override some of these numbers in the inode structure. */ - setup_rock_ridge(raw_de, inode, &chr, &len); + setup_rock_ridge(raw_de, inode, &rs); repeat: - while (len > 2) { /* There may be one byte for padding somewhere */ - rr = (struct rock_ridge *)chr; + while (rs.len > 2) { /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *)rs.chr; if (rr->len < 3) goto out; /* Something got screwed up here */ - sig = isonum_721(chr); - chr += rr->len; - len -= rr->len; - if (len < 0) + sig = isonum_721(rs.chr); + rs.chr += rr->len; + rs.len -= rr->len; + if (rs.len < 0) goto out; /* corrupted isofs */ switch (sig) { @@ -596,15 +617,18 @@ repeat: break; case SIG('C', 'E'): /* This tells is if there is a continuation record */ - cont_extent = isonum_733(rr->u.CE.extent); - cont_offset = isonum_733(rr->u.CE.offset); - cont_size = isonum_733(rr->u.CE.size); + rs.cont_extent = isonum_733(rr->u.CE.extent); + rs.cont_offset = isonum_733(rr->u.CE.offset); + rs.cont_size = isonum_733(rr->u.CE.size); default: break; } } - MAYBE_CONTINUE(repeat, inode); - kfree(buffer); + ret = rock_continue(&rs); + if (ret == 0) + goto repeat; + if (ret < 0) + goto fail; if (rpnt == link) goto fail; @@ -618,8 +642,7 @@ repeat: /* error exit from macro */ out: - if (buffer) - kfree(buffer); + kfree(rs.buffer); goto fail; out_noread: printk("unable to read i-node block"); -- cgit v0.10.2 From 7373909de403d229979842081c63917452e39402 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:47 -0700 Subject: [PATCH] rock: comment tidies Be a bit more standard in comment layout. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index efefbcce..977dd70 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -13,12 +13,14 @@ #include "isofs.h" #include "rock.h" -/* These functions are designed to read the system areas of a directory record +/* + * These functions are designed to read the system areas of a directory record * and extract relevant information. There are different functions provided * depending upon what information we need at the time. One function fills * out an inode structure, a second one extracts a filename, a third one * returns a symbolic link name, and a fourth one returns the extent number - * for the file. */ + * for the file. + */ #define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ @@ -34,7 +36,7 @@ struct rock_state { /* * This is a way of ensuring that we have something in the system - * use fields that is compatible with Rock Ridge. Return zero on success. + * use fields that is compatible with Rock Ridge. Return zero on success. */ static int check_sp(struct rock_ridge *rr, struct inode *inode) @@ -111,7 +113,9 @@ out: return ret; } -/* return length of name field; 0: not found, -1: to be ignored */ +/* + * return length of name field; 0: not found, -1: to be ignored + */ int get_rock_ridge_filename(struct iso_directory_record *de, char *retname, struct inode *inode) { @@ -535,8 +539,11 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode) { int result = parse_rock_ridge_inode_internal(de, inode, 0); - /* if rockridge flag was reset and we didn't look for attributes - * behind eventual XA attributes, have a look there */ + + /* + * if rockridge flag was reset and we didn't look for attributes + * behind eventual XA attributes, have a look there + */ if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1) && (ISOFS_SB(inode->i_sb)->s_rock == 2)) { result = parse_rock_ridge_inode_internal(de, inode, 14); @@ -544,9 +551,10 @@ int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode) return result; } -/* readpage() for symlinks: reads symlink contents into the page and either - makes it uptodate and returns 0 or returns error (-EIO) */ - +/* + * readpage() for symlinks: reads symlink contents into the page and either + * makes it uptodate and returns 0 or returns error (-EIO) + */ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; @@ -584,8 +592,10 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) if (offset + *pnt > bufsize) goto out_bad_span; - /* Now test for possible Rock Ridge extensions which will override - some of these numbers in the inode structure. */ + /* + * Now test for possible Rock Ridge extensions which will override + * some of these numbers in the inode structure. + */ setup_rock_ridge(raw_de, inode, &rs); -- cgit v0.10.2 From a089221c5e8a5ae8d74a919c8c7a4d2f68bd59e5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:48 -0700 Subject: [PATCH] rock: lindent rock.h So we have a couple of rock-ridge bugs. First up, rotoroot the poor thing into something which it is possible to work on. Feed rock.h through Lindent, tidy a couple of things by hand. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.h b/fs/isofs/rock.h index deaf5c8..9d3cbc7 100644 --- a/fs/isofs/rock.h +++ b/fs/isofs/rock.h @@ -1,85 +1,88 @@ -/* These structs are used by the system-use-sharing protocol, in which the - Rock Ridge extensions are embedded. It is quite possible that other - extensions are present on the disk, and this is fine as long as they - all use SUSP */ - -struct SU_SP{ - unsigned char magic[2]; - unsigned char skip; -} __attribute__((packed)); - -struct SU_CE{ - char extent[8]; - char offset[8]; - char size[8]; +/* + * These structs are used by the system-use-sharing protocol, in which the + * Rock Ridge extensions are embedded. It is quite possible that other + * extensions are present on the disk, and this is fine as long as they + * all use SUSP + */ + +struct SU_SP { + unsigned char magic[2]; + unsigned char skip; +} __attribute__ ((packed)); + +struct SU_CE { + char extent[8]; + char offset[8]; + char size[8]; }; -struct SU_ER{ - unsigned char len_id; - unsigned char len_des; - unsigned char len_src; - unsigned char ext_ver; - char data[0]; -} __attribute__((packed)); - -struct RR_RR{ - char flags[1]; -} __attribute__((packed)); - -struct RR_PX{ - char mode[8]; - char n_links[8]; - char uid[8]; - char gid[8]; +struct SU_ER { + unsigned char len_id; + unsigned char len_des; + unsigned char len_src; + unsigned char ext_ver; + char data[0]; +} __attribute__ ((packed)); + +struct RR_RR { + char flags[1]; +} __attribute__ ((packed)); + +struct RR_PX { + char mode[8]; + char n_links[8]; + char uid[8]; + char gid[8]; }; -struct RR_PN{ - char dev_high[8]; - char dev_low[8]; +struct RR_PN { + char dev_high[8]; + char dev_low[8]; }; +struct SL_component { + unsigned char flags; + unsigned char len; + char text[0]; +} __attribute__ ((packed)); -struct SL_component{ - unsigned char flags; - unsigned char len; - char text[0]; -} __attribute__((packed)); +struct RR_SL { + unsigned char flags; + struct SL_component link; +} __attribute__ ((packed)); -struct RR_SL{ - unsigned char flags; - struct SL_component link; -} __attribute__((packed)); +struct RR_NM { + unsigned char flags; + char name[0]; +} __attribute__ ((packed)); -struct RR_NM{ - unsigned char flags; - char name[0]; -} __attribute__((packed)); - -struct RR_CL{ - char location[8]; +struct RR_CL { + char location[8]; }; -struct RR_PL{ - char location[8]; +struct RR_PL { + char location[8]; }; -struct stamp{ - char time[7]; -} __attribute__((packed)); +struct stamp { + char time[7]; +} __attribute__ ((packed)); -struct RR_TF{ - char flags; - struct stamp times[0]; /* Variable number of these beasts */ -} __attribute__((packed)); +struct RR_TF { + char flags; + struct stamp times[0]; /* Variable number of these beasts */ +} __attribute__ ((packed)); /* Linux-specific extension for transparent decompression */ -struct RR_ZF{ - char algorithm[2]; - char parms[2]; - char real_size[8]; +struct RR_ZF { + char algorithm[2]; + char parms[2]; + char real_size[8]; }; -/* These are the bits and their meanings for flags in the TF structure. */ +/* + * These are the bits and their meanings for flags in the TF structure. + */ #define TF_CREATE 1 #define TF_MODIFY 2 #define TF_ACCESS 4 @@ -89,31 +92,31 @@ struct RR_ZF{ #define TF_EFFECTIVE 64 #define TF_LONG_FORM 128 -struct rock_ridge{ - char signature[2]; - unsigned char len; - unsigned char version; - union{ - struct SU_SP SP; - struct SU_CE CE; - struct SU_ER ER; - struct RR_RR RR; - struct RR_PX PX; - struct RR_PN PN; - struct RR_SL SL; - struct RR_NM NM; - struct RR_CL CL; - struct RR_PL PL; - struct RR_TF TF; - struct RR_ZF ZF; - } u; +struct rock_ridge { + char signature[2]; + unsigned char len; + unsigned char version; + union { + struct SU_SP SP; + struct SU_CE CE; + struct SU_ER ER; + struct RR_RR RR; + struct RR_PX PX; + struct RR_PN PN; + struct RR_SL SL; + struct RR_NM NM; + struct RR_CL CL; + struct RR_PL PL; + struct RR_TF TF; + struct RR_ZF ZF; + } u; }; -#define RR_PX 1 /* POSIX attributes */ -#define RR_PN 2 /* POSIX devices */ -#define RR_SL 4 /* Symbolic link */ -#define RR_NM 8 /* Alternate Name */ -#define RR_CL 16 /* Child link */ -#define RR_PL 32 /* Parent link */ -#define RR_RE 64 /* Relocation directory */ -#define RR_TF 128 /* Timestamps */ +#define RR_PX 1 /* POSIX attributes */ +#define RR_PN 2 /* POSIX devices */ +#define RR_SL 4 /* Symbolic link */ +#define RR_NM 8 /* Alternate Name */ +#define RR_CL 16 /* Child link */ +#define RR_PL 32 /* Parent link */ +#define RR_RE 64 /* Relocation directory */ +#define RR_TF 128 /* Timestamps */ -- cgit v0.10.2 From 9eb7f2c67c41d2cd730aedcd23e5baca09211d03 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:49 -0700 Subject: [PATCH] isofs: remove debug stuff isofs/inode.c: - Remove some crufty leak detection code - coding style cleanups - kfree(NULL) is permitted. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index abd7b12..72cc972 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -28,11 +28,6 @@ #define BEQUIET -#ifdef LEAK_CHECK -static int check_malloc; -static int check_bread; -#endif - static int isofs_hashi(struct dentry *parent, struct qstr *qstr); static int isofs_hash(struct dentry *parent, struct qstr *qstr); static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); @@ -55,11 +50,6 @@ static void isofs_put_super(struct super_block *sb) } #endif -#ifdef LEAK_CHECK - printk("Outstanding mallocs:%d, outstanding buffers: %d\n", - check_malloc, check_bread); -#endif - kfree(sbi); sb->s_fs_info = NULL; return; @@ -73,7 +63,7 @@ static kmem_cache_t *isofs_inode_cachep; static struct inode *isofs_alloc_inode(struct super_block *sb) { struct iso_inode_info *ei; - ei = (struct iso_inode_info *)kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL); + ei = kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; @@ -84,9 +74,9 @@ static void isofs_destroy_inode(struct inode *inode) kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) { - struct iso_inode_info *ei = (struct iso_inode_info *) foo; + struct iso_inode_info *ei = foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) @@ -107,7 +97,8 @@ static int init_inodecache(void) static void destroy_inodecache(void) { if (kmem_cache_destroy(isofs_inode_cachep)) - printk(KERN_INFO "iso_inode_cache: not all structures were freed\n"); + printk(KERN_INFO "iso_inode_cache: not all structures were " + "freed\n"); } static int isofs_remount(struct super_block *sb, int *flags, char *data) @@ -144,7 +135,7 @@ static struct dentry_operations isofs_dentry_ops[] = { { .d_hash = isofs_hashi_ms, .d_compare = isofs_dentry_cmpi_ms, - } + }, #endif }; @@ -219,8 +210,8 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms) /* * Case insensitive compare of two isofs names. */ -static int -isofs_dentry_cmpi_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms) +static int isofs_dentry_cmpi_common(struct dentry *dentry, struct qstr *a, + struct qstr *b, int ms) { int alen, blen; @@ -243,8 +234,8 @@ isofs_dentry_cmpi_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int /* * Case sensitive compare of two isofs names. */ -static int -isofs_dentry_cmp_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms) +static int isofs_dentry_cmp_common(struct dentry *dentry, struct qstr *a, + struct qstr *b, int ms) { int alen, blen; @@ -356,7 +347,7 @@ static match_table_t tokens = { {Opt_err, NULL} }; -static int parse_options(char *options, struct iso9660_options * popt) +static int parse_options(char *options, struct iso9660_options *popt) { char *p; int option; @@ -493,7 +484,7 @@ static int parse_options(char *options, struct iso9660_options * popt) */ #define WE_OBEY_THE_WRITTEN_STANDARDS 1 -static unsigned int isofs_get_last_session(struct super_block *sb,s32 session ) +static unsigned int isofs_get_last_session(struct super_block *sb, s32 session) { struct cdrom_multisession ms_info; unsigned int vol_desc_start; @@ -518,7 +509,8 @@ static unsigned int isofs_get_last_session(struct super_block *sb,s32 session ) printk(KERN_ERR "Invalid session number or type of track\n"); } i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info); - if(session > 0) printk(KERN_ERR "Invalid session number\n"); + if (session > 0) + printk(KERN_ERR "Invalid session number\n"); #if 0 printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i); if (i==0) { @@ -557,13 +549,13 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) struct iso9660_options opt; struct isofs_sb_info * sbi; - sbi = kmalloc(sizeof(struct isofs_sb_info), GFP_KERNEL); + sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) return -ENOMEM; s->s_fs_info = sbi; - memset(sbi, 0, sizeof(struct isofs_sb_info)); + memset(sbi, 0, sizeof(*sbi)); - if (!parse_options((char *) data, &opt)) + if (!parse_options((char *)data, &opt)) goto out_freesbi; /* @@ -1002,7 +994,6 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s, rv++; } - abort: unlock_kernel(); return rv; @@ -1014,7 +1005,7 @@ abort: static int isofs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { - if ( create ) { + if (create) { printk("isofs_get_block: Kernel tries to allocate a block\n"); return -EROFS; } @@ -1061,19 +1052,17 @@ static struct address_space_operations isofs_aops = { static inline void test_and_set_uid(uid_t *p, uid_t value) { - if(value) { + if (value) *p = value; - } } static inline void test_and_set_gid(gid_t *p, gid_t value) { - if(value) { + if (value) *p = value; - } } -static int isofs_read_level3_size(struct inode * inode) +static int isofs_read_level3_size(struct inode *inode) { unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra; @@ -1136,7 +1125,7 @@ static int isofs_read_level3_size(struct inode * inode) bh = sb_bread(inode->i_sb, block); if (!bh) goto out_noread; - memcpy((void *) tmpde + slop, bh->b_data, offset); + memcpy((void *)tmpde+slop, bh->b_data, offset); } de = tmpde; } @@ -1150,12 +1139,11 @@ static int isofs_read_level3_size(struct inode * inode) more_entries = de->flags[-high_sierra] & 0x80; i++; - if(i > 100) + if (i > 100) goto out_toomany; - } while(more_entries); + } while (more_entries); out: - if (tmpde) - kfree(tmpde); + kfree(tmpde); if (bh) brelse(bh); return 0; @@ -1179,7 +1167,7 @@ out_toomany: goto out; } -static void isofs_read_inode(struct inode * inode) +static void isofs_read_inode(struct inode *inode) { struct super_block *sb = inode->i_sb; struct isofs_sb_info *sbi = ISOFS_SB(sb); @@ -1249,7 +1237,7 @@ static void isofs_read_inode(struct inode * inode) ei->i_format_parm[2] = 0; ei->i_section_size = isonum_733 (de->size); - if(de->flags[-high_sierra] & 0x80) { + if (de->flags[-high_sierra] & 0x80) { if(isofs_read_level3_size(inode)) goto fail; } else { ei->i_next_section_block = 0; @@ -1336,16 +1324,16 @@ static void isofs_read_inode(struct inode * inode) /* XXX - parse_rock_ridge_inode() had already set i_rdev. */ init_special_inode(inode, inode->i_mode, inode->i_rdev); - out: +out: if (tmpde) kfree(tmpde); if (bh) brelse(bh); return; - out_badread: +out_badread: printk(KERN_WARNING "ISOFS: unable to read i-node block\n"); - fail: +fail: make_bad_inode(inode); goto out; } @@ -1394,11 +1382,8 @@ struct inode *isofs_iget(struct super_block *sb, hashval = (block << sb->s_blocksize_bits) | offset; - inode = iget5_locked(sb, - hashval, - &isofs_iget5_test, - &isofs_iget5_set, - &data); + inode = iget5_locked(sb, hashval, &isofs_iget5_test, + &isofs_iget5_set, &data); if (inode && (inode->i_state & I_NEW)) { sb->s_op->read_inode(inode); @@ -1408,36 +1393,6 @@ struct inode *isofs_iget(struct super_block *sb, return inode; } -#ifdef LEAK_CHECK -#undef malloc -#undef free_s -#undef sb_bread -#undef brelse - -void * leak_check_malloc(unsigned int size){ - void * tmp; - check_malloc++; - tmp = kmalloc(size, GFP_KERNEL); - return tmp; -} - -void leak_check_free_s(void * obj, int size){ - check_malloc--; - return kfree(obj); -} - -struct buffer_head * leak_check_bread(struct super_block *sb, int block){ - check_bread++; - return sb_bread(sb, block); -} - -void leak_check_brelse(struct buffer_head * bh){ - check_bread--; - return brelse(bh); -} - -#endif - static struct super_block *isofs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { -- cgit v0.10.2 From e595447e177b39aa6c96baaa57b30cde2d8b9df7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:50 -0700 Subject: [PATCH] rock.c: handle corrupted directories The bug in rock.c is that it's totally trusting of the contents of the directories. If the directory says there's a continuation 10000 bytes into this 4k block then we cheerily poke around in memory we don't own and oops. So change rock_continue() to apply various sanity checks, at least ensuring that the offset+length remain within the bounds for the header part of a struct rock_ridge directory entry. Note that the kernel can still overindex the buffer due to the variable size of the rock-ridge directory entries. We cannot check that in rock_continue() unless we go parse the directory entry's signature and work out its size. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 977dd70..9a81830 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -81,9 +81,22 @@ static void init_rock_state(struct rock_state *rs, struct inode *inode) static int rock_continue(struct rock_state *rs) { int ret = 1; + int blocksize = 1 << rs->inode->i_blkbits; + const int min_de_size = offsetof(struct rock_ridge, u); kfree(rs->buffer); rs->buffer = NULL; + + if ((unsigned)rs->cont_offset > blocksize - min_de_size || + (unsigned)rs->cont_size > blocksize || + (unsigned)(rs->cont_offset + rs->cont_size) > blocksize) { + printk(KERN_NOTICE "rock: corrupted directory entry. " + "extent=%d, offset=%d, size=%d\n", + rs->cont_extent, rs->cont_offset, rs->cont_size); + ret = -EIO; + goto out; + } + if (rs->cont_extent) { struct buffer_head *bh; -- cgit v0.10.2 From 642217c17b9a56c7e4cf48f6a13dfd5e4a4c2e10 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:51 -0700 Subject: [PATCH] rock: rename union members The silly thing does: struct foo { ... }; ... #define foo 42 so you can no longer refer to `struct foo' in C code. Rename the structures. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.h b/fs/isofs/rock.h index 9d3cbc7..ed09e2b 100644 --- a/fs/isofs/rock.h +++ b/fs/isofs/rock.h @@ -5,18 +5,18 @@ * all use SUSP */ -struct SU_SP { +struct SU_SP_s { unsigned char magic[2]; unsigned char skip; } __attribute__ ((packed)); -struct SU_CE { +struct SU_CE_s { char extent[8]; char offset[8]; char size[8]; }; -struct SU_ER { +struct SU_ER_s { unsigned char len_id; unsigned char len_des; unsigned char len_src; @@ -24,18 +24,18 @@ struct SU_ER { char data[0]; } __attribute__ ((packed)); -struct RR_RR { +struct RR_RR_s { char flags[1]; } __attribute__ ((packed)); -struct RR_PX { +struct RR_PX_s { char mode[8]; char n_links[8]; char uid[8]; char gid[8]; }; -struct RR_PN { +struct RR_PN_s { char dev_high[8]; char dev_low[8]; }; @@ -46,21 +46,21 @@ struct SL_component { char text[0]; } __attribute__ ((packed)); -struct RR_SL { +struct RR_SL_s { unsigned char flags; struct SL_component link; } __attribute__ ((packed)); -struct RR_NM { +struct RR_NM_s { unsigned char flags; char name[0]; } __attribute__ ((packed)); -struct RR_CL { +struct RR_CL_s { char location[8]; }; -struct RR_PL { +struct RR_PL_s { char location[8]; }; @@ -68,13 +68,13 @@ struct stamp { char time[7]; } __attribute__ ((packed)); -struct RR_TF { +struct RR_TF_s { char flags; struct stamp times[0]; /* Variable number of these beasts */ } __attribute__ ((packed)); /* Linux-specific extension for transparent decompression */ -struct RR_ZF { +struct RR_ZF_s { char algorithm[2]; char parms[2]; char real_size[8]; @@ -97,18 +97,18 @@ struct rock_ridge { unsigned char len; unsigned char version; union { - struct SU_SP SP; - struct SU_CE CE; - struct SU_ER ER; - struct RR_RR RR; - struct RR_PX PX; - struct RR_PN PN; - struct RR_SL SL; - struct RR_NM NM; - struct RR_CL CL; - struct RR_PL PL; - struct RR_TF TF; - struct RR_ZF ZF; + struct SU_SP_s SP; + struct SU_CE_s CE; + struct SU_ER_s ER; + struct RR_RR_s RR; + struct RR_PX_s PX; + struct RR_PN_s PN; + struct RR_SL_s SL; + struct RR_NM_s NM; + struct RR_CL_s CL; + struct RR_PL_s PL; + struct RR_TF_s TF; + struct RR_ZF_s ZF; } u; }; -- cgit v0.10.2 From f2966632a134e865db3c819346a1dc7d96e05309 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:51 -0700 Subject: [PATCH] rock: handle directory overflows Handle the case where the variable-sized part of a rock-ridge directory entry overhangs the end of the buffer which we allocated for it. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 9a81830..4326cb4 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -127,6 +127,66 @@ out: } /* + * We think there's a record of type `sig' at rs->chr. Parse the signature + * and make sure that there's really room for a record of that type. + */ +static int rock_check_overflow(struct rock_state *rs, int sig) +{ + int len; + + switch (sig) { + case SIG('S', 'P'): + len = sizeof(struct SU_SP_s); + break; + case SIG('C', 'E'): + len = sizeof(struct SU_CE_s); + break; + case SIG('E', 'R'): + len = sizeof(struct SU_ER_s); + break; + case SIG('R', 'R'): + len = sizeof(struct RR_RR_s); + break; + case SIG('P', 'X'): + len = sizeof(struct RR_PX_s); + break; + case SIG('P', 'N'): + len = sizeof(struct RR_PN_s); + break; + case SIG('S', 'L'): + len = sizeof(struct RR_SL_s); + break; + case SIG('N', 'M'): + len = sizeof(struct RR_NM_s); + break; + case SIG('C', 'L'): + len = sizeof(struct RR_CL_s); + break; + case SIG('P', 'L'): + len = sizeof(struct RR_PL_s); + break; + case SIG('T', 'F'): + len = sizeof(struct RR_TF_s); + break; + case SIG('Z', 'F'): + len = sizeof(struct RR_ZF_s); + break; + default: + len = 0; + break; + } + len += offsetof(struct rock_ridge, u); + if (len > rs->len) { + printk(KERN_NOTICE "rock: directory entry would overflow " + "storage\n"); + printk(KERN_NOTICE "rock: sig=0x%02x, size=%d, remaining=%d\n", + sig, len, rs->len); + return -EIO; + } + return 0; +} + +/* * return length of name field; 0: not found, -1: to be ignored */ int get_rock_ridge_filename(struct iso_directory_record *de, @@ -152,10 +212,12 @@ repeat: if (rr->len < 3) goto out; /* Something got screwed up here */ sig = isonum_721(rs.chr); + if (rock_check_overflow(&rs, sig)) + goto eio; rs.chr += rr->len; rs.len -= rr->len; if (rs.len < 0) - goto out; /* corrupted isofs */ + goto eio; /* corrupted isofs */ switch (sig) { case SIG('R', 'R'): @@ -213,6 +275,9 @@ repeat: out: kfree(rs.buffer); return ret; +eio: + ret = -EIO; + goto out; } static int @@ -245,10 +310,12 @@ repeat: if (rr->len < 3) goto out; /* Something got screwed up here */ sig = isonum_721(rs.chr); + if (rock_check_overflow(&rs, sig)) + goto eio; rs.chr += rr->len; rs.len -= rr->len; if (rs.len < 0) - goto out; /* corrupted isofs */ + goto eio; /* corrupted isofs */ switch (sig) { #ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ @@ -479,6 +546,9 @@ repeat: out: kfree(rs.buffer); return ret; +eio: + ret = -EIO; + goto out; } static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) @@ -618,6 +688,8 @@ repeat: if (rr->len < 3) goto out; /* Something got screwed up here */ sig = isonum_721(rs.chr); + if (rock_check_overflow(&rs, sig)) + goto out; rs.chr += rr->len; rs.len -= rr->len; if (rs.len < 0) -- cgit v0.10.2 From 9769f4eb3fad2dd53a5d24c81ee5f7f05450742b Mon Sep 17 00:00:00 2001 From: Jeremy White Date: Tue, 21 Jun 2005 17:16:53 -0700 Subject: [PATCH] isofs: show hidden files, add granularity for assoc/hidden files flags The current isofs treatment of hidden files is flawed in two ways. First, it does not provide sufficient granularity; it hides both 'hidden' files and 'associated' files (resource fork for Mac files). Second, the default behavior to completely strip hidden files, while an admirable implementation of the spec, is a poor choice given the real world use of hidden files as a poor mans copy protection scheme for MSDOS and Windows based systems. A longer description of this is available here: http://www.uwsg.iu.edu/hypermail/linux/kernel/0205.3/0267.html This patch was originally built after a few private conversations with Alan Cox; I shamefully failed to persist in seeing it go forward, I hope to make amends now. This patch introduces granularity by allowing explicit control for both hidden and associated files. It also reverses the default so that by default, hidden files are treated as regular files on the iso9660 file system. This allow Wine to process Windows CDs, including those that are hybrid Mac/Windows CDs properly and completely, without our having to go muck up peoples fstabs as we do now. (I have tested this with such a hybrid + hidden CD and have verified that this patch works as claimed). Signed-off-by: Jeremy White Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/filesystems/isofs.txt b/Documentation/filesystems/isofs.txt index f64a105..424585f 100644 --- a/Documentation/filesystems/isofs.txt +++ b/Documentation/filesystems/isofs.txt @@ -26,7 +26,11 @@ Mount options unique to the isofs filesystem. mode=xxx Sets the permissions on files to xxx nojoliet Ignore Joliet extensions if they are present. norock Ignore Rock Ridge extensions if they are present. - unhide Show hidden files. + hide Completely strip hidden files from the file system. + showassoc Show files marked with the 'associated' bit + unhide Deprecated; showing hidden files is now default; + If given, it is a synonym for 'showassoc' which will + recreate previous unhide behavior session=x Select number of session on multisession CD sbsector=xxx Session begins from sector xxx diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index 6030956..7901ac9 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c @@ -193,12 +193,17 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, /* Handle everything else. Do name translation if there is no Rock Ridge NM field. */ - if (sbi->s_unhide == 'n') { - /* Do not report hidden or associated files */ - if (de->flags[-sbi->s_high_sierra] & 5) { - filp->f_pos += de_len; - continue; - } + + /* + * Do not report hidden files if so instructed, or associated + * files unless instructed to do so + */ + if ((sbi->s_hide == 'y' && + (de->flags[-sbi->s_high_sierra] & 1)) || + (sbi->s_showassoc =='n' && + (de->flags[-sbi->s_high_sierra] & 4))) { + filp->f_pos += de_len; + continue; } map = 1; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 72cc972..1652de1 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -144,7 +144,8 @@ struct iso9660_options{ char rock; char joliet; char cruft; - char unhide; + char hide; + char showassoc; char nocompress; unsigned char check; unsigned int blocksize; @@ -309,13 +310,15 @@ enum { Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, - Opt_nocompress, + Opt_nocompress, Opt_hide, Opt_showassoc, }; static match_table_t tokens = { {Opt_norock, "norock"}, {Opt_nojoliet, "nojoliet"}, {Opt_unhide, "unhide"}, + {Opt_hide, "hide"}, + {Opt_showassoc, "showassoc"}, {Opt_cruft, "cruft"}, {Opt_utf8, "utf8"}, {Opt_iocharset, "iocharset=%s"}, @@ -356,7 +359,8 @@ static int parse_options(char *options, struct iso9660_options *popt) popt->rock = 'y'; popt->joliet = 'y'; popt->cruft = 'n'; - popt->unhide = 'n'; + popt->hide = 'n'; + popt->showassoc = 'n'; popt->check = 'u'; /* unset */ popt->nocompress = 0; popt->blocksize = 1024; @@ -389,8 +393,12 @@ static int parse_options(char *options, struct iso9660_options *popt) case Opt_nojoliet: popt->joliet = 'n'; break; + case Opt_hide: + popt->hide = 'y'; + break; case Opt_unhide: - popt->unhide = 'y'; + case Opt_showassoc: + popt->showassoc = 'y'; break; case Opt_cruft: popt->cruft = 'y'; @@ -784,7 +792,8 @@ root_found: sbi->s_rock = (opt.rock == 'y' ? 2 : 0); sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ sbi->s_cruft = opt.cruft; - sbi->s_unhide = opt.unhide; + sbi->s_hide = opt.hide; + sbi->s_showassoc = opt.showassoc; sbi->s_uid = opt.uid; sbi->s_gid = opt.gid; sbi->s_utf8 = opt.utf8; diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index 9ce7b51..38c7515 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h @@ -47,6 +47,8 @@ struct isofs_sb_info { unsigned char s_nosuid; unsigned char s_nodev; unsigned char s_nocompress; + unsigned char s_hide; + unsigned char s_showassoc; mode_t s_mode; gid_t s_gid; diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 690edf3..e37e82b 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -131,14 +131,16 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, } /* - * Skip hidden or associated files unless unhide is set + * Skip hidden or associated files unless hide or showassoc, + * respectively, is set */ match = 0; if (dlen > 0 && - (!(de->flags[-sbi->s_high_sierra] & 5) - || sbi->s_unhide == 'y')) - { - match = (isofs_cmp(dentry,dpnt,dlen) == 0); + (sbi->s_hide =='n' || + (!(de->flags[-sbi->s_high_sierra] & 1))) && + (sbi->s_showassoc =='y' || + (!(de->flags[-sbi->s_high_sierra] & 4)))) { + match = (isofs_cmp(dentry, dpnt, dlen) == 0); } if (match) { isofs_normalize_block_and_offset(de, @@ -146,11 +148,11 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, &offset_saved); *block_rv = block_saved; *offset_rv = offset_saved; - if (bh) brelse(bh); + brelse(bh); return 1; } } - if (bh) brelse(bh); + brelse(bh); return 0; } -- cgit v0.10.2 From e6afbe59710f65d92d00de1f3adb5514ef634110 Mon Sep 17 00:00:00 2001 From: Keenan Pepper Date: Tue, 21 Jun 2005 17:16:54 -0700 Subject: [PATCH] Bring back Tux on Chips 65550 framebuffer I don't see any reason why the framebuffer should need to be cleared, and it makes Tux vanish. Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index ab98f22..95e7255 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -423,9 +423,6 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) pmu_register_sleep_notifier(&chips_sleep_notifier); #endif /* CONFIG_PMAC_PBOOK */ - /* Clear the entire framebuffer */ - memset(p->screen_base, 0, 0x100000); - pci_set_drvdata(dp, p); return 0; } -- cgit v0.10.2 From 27f931dac93057bbae691f66a49b11ff2f483bee Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:55 -0700 Subject: [PATCH] s1d13xxxfb linkage fix s1d13xxxfb_remove() is referenced from s1d13xxxfb_probe(), which is marked __devinit(). So s1d13xxxfb_remove() cannot be marked __devexit. Does this all make sense? Clearly the __devexit section will still be in core when the __devinit code is run, if the driver was loaded as a module. But I suppose that if the driver is statically linked, the __devexit section might be dropped early in boot. Still, we wouldn't drop __devexit prior to initcall completion, at which point the __devinit code has all been run anyway. verdict: this code was legal and made sense. Is this a generic problem, or an arm-specific problem? UPD include/linux/compile.h CC init/version.o LD init/built-in.o LD .tmp_vmlinux1 `.exit.text' referenced in section `.init.text' of drivers/built-in.o: defined in discarded section `.exit.text' of drivers/built-in.o Cc: Russell King Cc: Rusty Russell Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index b637c38..789de13 100644 --- a/drivers/video/s1d13xxxfb.c +++ b/drivers/video/s1d13xxxfb.c @@ -493,7 +493,7 @@ s1d13xxxfb_fetch_hw_state(struct fb_info *info) } -static int __devexit +static int s1d13xxxfb_remove(struct device *dev) { struct fb_info *info = dev_get_drvdata(dev); -- cgit v0.10.2 From 78c03717c415d81879e4dac2e452d1a0d3738a80 Mon Sep 17 00:00:00 2001 From: Gerd Knorr Date: Tue, 21 Jun 2005 17:16:56 -0700 Subject: [PATCH] some vesafb fixes Fix the size passed to release_mem_region in an error path. Also adjust the message printed when vesafb cannot load; the comment there already says this must not be fatal, so the message should also not mention the word 'abort' otherwise indicating a problem to worry about in the log. Signed-off-by: Jan Beulich Signed-off-by: Gerd Knorr Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 3027841..f3069b0 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -271,7 +271,7 @@ static int __init vesafb_probe(struct device *device) if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) { printk(KERN_WARNING - "vesafb: abort, cannot reserve video memory at 0x%lx\n", + "vesafb: cannot reserve video memory at 0x%lx\n", vesafb_fix.smem_start); /* We cannot make this fatal. Sometimes this comes from magic spaces our resource handlers simply don't know about */ @@ -279,13 +279,13 @@ static int __init vesafb_probe(struct device *device) info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); if (!info) { - release_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len); + release_mem_region(vesafb_fix.smem_start, size_total); return -ENOMEM; } info->pseudo_palette = info->par; info->par = NULL; - info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); + info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); if (!info->screen_base) { printk(KERN_ERR "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", @@ -386,7 +386,7 @@ static int __init vesafb_probe(struct device *device) request_region(0x3c0, 32, "vesafb"); if (mtrr) { - int temp_size = size_total; + unsigned int temp_size = size_total; /* Find the largest power-of-two */ while (temp_size & (temp_size - 1)) temp_size &= (temp_size - 1); -- cgit v0.10.2 From 5a3b5899f190a365eed806302f4b58a493233f96 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Jun 2005 17:16:57 -0700 Subject: [PATCH] intelfbdrv naming fix Can't use this fancy name, because it's used to generate a sysfs filename: kobject_register failed for Intel(R) 830M/845G/852GM/855GM/865G/915G Framebuffer Driver (-13) [] kobject_register+0x43/0x70 [] bus_add_driver+0x52/0xa0 [] pci_device_shutdown+0x0/0x20 [] pci_register_driver+0x61/0x80 [] intelfb_init+0x59/0x70 [] do_initcalls+0x2c/0xc0 [] kern_mount+0x15/0x17 [] init+0x0/0x100 [] init+0x2a/0x100 [] kernel_thread_helper+0x0/0x18 [] kernel_thread_helper+0x5/0x18 Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 25f9a9a..94f35a6 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -214,7 +214,7 @@ static struct fb_ops intel_fb_ops = { /* PCI driver module table */ static struct pci_driver intelfb_driver = { - .name = "Intel(R) " SUPPORTED_CHIPSETS " Framebuffer Driver", + .name = "intelfb", .id_table = intelfb_pci_table, .probe = intelfb_pci_register, .remove = __devexit_p(intelfb_pci_unregister) -- cgit v0.10.2 From f5a9951c94e7a285a3d00648e3d790a7f016bd11 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Tue, 21 Jun 2005 17:16:58 -0700 Subject: [PATCH] fbdev: iomove removal Since no one is using the inbuf, outbuf of struct fb_pixmap I removed their use in the framebuffer console. The idea is instead move the pixmap functionality below the accelerated functions intead of on top as the way it is now. If there is no objection please apply. This is against Linus latestr GIT tree. Thank you. Signed-off-by: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index b28a4b0..4eef207 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -107,13 +107,6 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, const unsigned short *s, int count, int yy, int xx, int fg, int bg) { - void (*move_unaligned)(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 idx, - u32 height, u32 shift_high, u32 shift_low, - u32 mod); - void (*move_aligned)(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, - u32 height); unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; unsigned int width = (vc->vc_font.width + 7) >> 3; unsigned int cellsize = vc->vc_font.height * width; @@ -141,13 +134,6 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, image.height = vc->vc_font.height; image.depth = 1; - if (info->pixmap.outbuf && info->pixmap.inbuf) { - move_aligned = fb_iomove_buf_aligned; - move_unaligned = fb_iomove_buf_unaligned; - } else { - move_aligned = fb_sysmove_buf_aligned; - move_unaligned = fb_sysmove_buf_unaligned; - } while (count) { if (count > maxcnt) cnt = k = maxcnt; @@ -171,7 +157,7 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, src = buf; } - move_unaligned(info, &info->pixmap, dst, pitch, + fb_sysmove_buf_unaligned(info, &info->pixmap, dst, pitch, src, idx, image.height, shift_high, shift_low, mod); shift_low += mod; @@ -189,7 +175,7 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, src = buf; } - move_aligned(info, &info->pixmap, dst, pitch, + fb_sysmove_buf_aligned(info, &info->pixmap, dst, pitch, src, idx, image.height); dst += width; } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 8cef020..78907a8 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -76,65 +76,21 @@ int fb_get_color_depth(struct fb_var_screeninfo *var) EXPORT_SYMBOL(fb_get_color_depth); /* - * Drawing helpers. + * Data padding functions. */ -void fb_iomove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, - u32 height) -{ - int i; - - for (i = height; i--; ) { - buf->outbuf(info, dst, src, s_pitch); - src += s_pitch; - dst += d_pitch; - } -} - void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height) { - int i, j; + int i; for (i = height; i--; ) { - for (j = 0; j < s_pitch; j++) - dst[j] = src[j]; + memcpy(dst, src, s_pitch); src += s_pitch; dst += d_pitch; } } - -void fb_iomove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 idx, - u32 height, u32 shift_high, u32 shift_low, - u32 mod) -{ - u8 mask = (u8) (0xfff << shift_high), tmp; - int i, j; - - for (i = height; i--; ) { - for (j = 0; j < idx; j++) { - tmp = buf->inbuf(info, dst+j); - tmp &= mask; - tmp |= *src >> shift_low; - buf->outbuf(info, dst+j, &tmp, 1); - tmp = *src << shift_high; - buf->outbuf(info, dst+j+1, &tmp, 1); - src++; - } - tmp = buf->inbuf(info, dst+idx); - tmp &= mask; - tmp |= *src >> shift_low; - buf->outbuf(info, dst+idx, &tmp, 1); - if (shift_high < mod) { - tmp = *src << shift_high; - buf->outbuf(info, dst+idx+1, &tmp, 1); - } - src++; - dst += d_pitch; - } -} +EXPORT_SYMBOL(fb_sysmove_buf_aligned); void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, u8 *dst, u32 d_pitch, u8 *src, u32 idx, @@ -166,6 +122,7 @@ void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, dst += d_pitch; } } +EXPORT_SYMBOL(fb_sysmove_buf_unaligned); /* * we need to lock this section since fb_cursor @@ -1357,10 +1314,6 @@ EXPORT_SYMBOL(fb_set_var); EXPORT_SYMBOL(fb_blank); EXPORT_SYMBOL(fb_pan_display); EXPORT_SYMBOL(fb_get_buffer_offset); -EXPORT_SYMBOL(fb_iomove_buf_unaligned); -EXPORT_SYMBOL(fb_iomove_buf_aligned); -EXPORT_SYMBOL(fb_sysmove_buf_unaligned); -EXPORT_SYMBOL(fb_sysmove_buf_aligned); EXPORT_SYMBOL(fb_set_suspend); EXPORT_SYMBOL(fb_register_client); EXPORT_SYMBOL(fb_unregister_client); diff --git a/drivers/video/softcursor.c b/drivers/video/softcursor.c index 13a4511..a6c5ca8 100644 --- a/drivers/video/softcursor.c +++ b/drivers/video/softcursor.c @@ -58,12 +58,8 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) } else memcpy(src, image->data, dsize); - if (info->pixmap.outbuf) - fb_iomove_buf_aligned(info, &info->pixmap, dst, d_pitch, src, - s_pitch, image->height); - else - fb_sysmove_buf_aligned(info, &info->pixmap, dst, d_pitch, src, - s_pitch, image->height); + fb_sysmove_buf_aligned(info, &info->pixmap, dst, d_pitch, src, + s_pitch, image->height); image->data = dst; info->fbops->fb_imageblit(info, image); diff --git a/include/linux/fb.h b/include/linux/fb.h index b468bf4..e149428 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -524,11 +524,11 @@ struct fb_pixmap { u32 offset; /* current offset to buffer */ u32 buf_align; /* byte alignment of each bitmap */ u32 scan_align; /* alignment per scanline */ - u32 access_align; /* alignment per read/write */ + u32 access_align; /* alignment per read/write (bits) */ u32 flags; /* see FB_PIXMAP_* */ /* access methods */ - void (*outbuf)(struct fb_info *info, u8 *addr, u8 *src, unsigned int size); - u8 (*inbuf) (struct fb_info *info, u8 *addr); + void (*writeio)(struct fb_info *info, void __iomem *dst, void *src, unsigned int size); + void (*readio) (struct fb_info *info, void *dst, void __iomem *src, unsigned int size); }; @@ -816,12 +816,6 @@ extern int unregister_framebuffer(struct fb_info *fb_info); extern int fb_prepare_logo(struct fb_info *fb_info); extern int fb_show_logo(struct fb_info *fb_info); extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size); -extern void fb_iomove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 idx, - u32 height, u32 shift_high, u32 shift_low, u32 mod); -extern void fb_iomove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, - u32 height); extern void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height, u32 shift_high, u32 shift_low, u32 mod); -- cgit v0.10.2 From 8d7f085342ddf20194b6e00c42b80968f15104db Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 21 Jun 2005 17:16:59 -0700 Subject: [PATCH] pm3fb typo fix Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 8e024aa..e0dad94 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -5,7 +5,7 @@ * Based on code written by: * Sven Luther, * Alan Hourihane, - * Russel King, + * Russell King, * Based on linux/drivers/video/skeletonfb.c: * Copyright (C) 1997 Geert Uytterhoeven * Based on linux/driver/video/pm2fb.c: -- cgit v0.10.2 From f18cd8f7053a1e6755d1c1396884b2bfa1577e54 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Tue, 21 Jun 2005 17:17:00 -0700 Subject: [PATCH] VGA to fbcon fix. Currently when going from vgacon to fbcon the VT screenbuffer are often different sizes. In the case when they are different sizes a new VT screenbuffer is allocated and the contents are copied into the new buffer. Currently the amount copied from VGA text memory to the new screenbuf is the size of the framebuffer console. If the framebuffer console new VT screen buffer is greater than the VGA text memory size then we get some of the VGA BIOS contents as well. This patch will only allow you to copy up to the size of VGA text memory now. The rest is filled with erase characters. Initial patch by Jordan Crouse Signed-off-by: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index bcf59b2..d27fa91 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -95,6 +95,7 @@ static unsigned long vgacon_uni_pagedir[2]; /* Description of the hardware situation */ static unsigned long vga_vram_base; /* Base of video memory */ static unsigned long vga_vram_end; /* End of video memory */ +static int vga_vram_size; /* Size of video memory */ static u16 vga_video_port_reg; /* Video register select port */ static u16 vga_video_port_val; /* Video register value port */ static unsigned int vga_video_num_columns; /* Number of text columns */ @@ -288,6 +289,7 @@ static const char __init *vgacon_startup(void) vga_vram_base = VGA_MAP_MEM(vga_vram_base); vga_vram_end = VGA_MAP_MEM(vga_vram_end); + vga_vram_size = vga_vram_end - vga_vram_base; /* * Find out if there is a graphics card present. @@ -504,9 +506,13 @@ static int vgacon_switch(struct vc_data *c) */ vga_video_num_columns = c->vc_cols; vga_video_num_lines = c->vc_rows; + + /* We can only copy out the size of the video buffer here, + * otherwise we get into VGA BIOS */ + if (!vga_is_gfx) scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, - c->vc_screenbuf_size); + c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); return 0; /* Redrawing not needed */ } @@ -961,7 +967,6 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) if (!lines) /* Turn scrollback off */ c->vc_visible_origin = c->vc_origin; else { - int vram_size = vga_vram_end - vga_vram_base; int margin = c->vc_size_row * 4; int ul, we, p, st; @@ -971,7 +976,7 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) we = vga_rolled_over + c->vc_size_row; } else { ul = 0; - we = vram_size; + we = vga_vram_size; } p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + lines * c->vc_size_row; @@ -1012,9 +1017,13 @@ static void vgacon_save_screen(struct vc_data *c) c->vc_x = ORIG_X; c->vc_y = ORIG_Y; } + + /* We can't copy in more then the size of the video buffer, + * or we'll be copying in VGA BIOS */ + if (!vga_is_gfx) scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, - c->vc_screenbuf_size); + c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); } static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, -- cgit v0.10.2 From 27aef2d49f9d82c58e65d72abcd636168ec19ac9 Mon Sep 17 00:00:00 2001 From: Sylvain Meyer Date: Tue, 21 Jun 2005 17:17:01 -0700 Subject: [PATCH] intelfb: Add voffset option to avoid conficts with Xorg i810 driver - Add voffset option to avoid conficts with Xorg i810 driver Signed-off-by: Sylvain Meyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 94f35a6..7a5750b 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -238,12 +238,15 @@ static int noregister = 0; static int probeonly = 0; static int idonly = 0; static int bailearly = 0; +static int voffset = 48; static char *mode = NULL; module_param(accel, bool, S_IRUGO); MODULE_PARM_DESC(accel, "Enable console acceleration"); module_param(vram, int, S_IRUGO); MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB"); +module_param(voffset, int, S_IRUGO); +MODULE_PARM_DESC(voffset, "Offset of framebuffer in MiB"); module_param(hwcursor, bool, S_IRUGO); MODULE_PARM_DESC(hwcursor, "Enable HW cursor"); module_param(mtrr, bool, S_IRUGO); @@ -503,6 +506,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) struct agp_bridge_data *bridge; int aperture_bar = 0; int mmio_bar = 1; + int offset; DBG_MSG("intelfb_pci_register\n"); @@ -659,17 +663,21 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENODEV; } + if (MB(voffset) < stolen_size) + offset = (stolen_size >> 12); + else + offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE; + /* set the mem offsets - set them after the already used pages */ if (dinfo->accel) { - dinfo->ring.offset = (stolen_size >> 12) - + gtt_info.current_memory; + dinfo->ring.offset = offset + gtt_info.current_memory; } if (dinfo->hwcursor) { - dinfo->cursor.offset = (stolen_size >> 12) + + dinfo->cursor.offset = offset + + gtt_info.current_memory + (dinfo->ring.size >> 12); } if (dinfo->fbmem_gart) { - dinfo->fb.offset = (stolen_size >> 12) + + dinfo->fb.offset = offset + + gtt_info.current_memory + (dinfo->ring.size >> 12) + (dinfo->cursor.size >> 12); } -- cgit v0.10.2 From df529338d9c5d9329e503955795c89472e1ba6e6 Mon Sep 17 00:00:00 2001 From: Sylvain Meyer Date: Tue, 21 Jun 2005 17:17:02 -0700 Subject: [PATCH] intelfb: fix accel detection when changing video modes Changed the tests in intelfb_set_par to check also the parameter var.accel_flags. If null, do nothing about ring buffers. Now, the DirectFB i830 driver could nicely work even if intelfb is hw accelerated. Just change the /etc/fb.modes file to disable console hw acceleration when starting a DirectFB app. Signed-off-by: Sylvain Meyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 7a5750b..448c908 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -1301,7 +1301,7 @@ intelfb_set_par(struct fb_info *info) intelfb_blank(FB_BLANK_POWERDOWN, info); - if (dinfo->accel) + if (ACCEL(dinfo, info)) intelfbhw_2d_stop(dinfo); memcpy(hw, &dinfo->save_state, sizeof(*hw)); @@ -1317,7 +1317,7 @@ intelfb_set_par(struct fb_info *info) update_dinfo(dinfo, &info->var); - if (dinfo->accel) + if (ACCEL(dinfo, info)) intelfbhw_2d_start(dinfo); intelfb_pan_display(&info->var, info); -- cgit v0.10.2 From 4ff45f515144d232c83bf55c53f54deecb750296 Mon Sep 17 00:00:00 2001 From: Sylvain Meyer Date: Tue, 21 Jun 2005 17:17:03 -0700 Subject: [PATCH] intelfb documentation Add a small documentation of the driver parameters. Signed-off-by: Sylvain Meyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/fb/intelfb.txt b/Documentation/fb/intelfb.txt new file mode 100644 index 0000000..c12d39a --- /dev/null +++ b/Documentation/fb/intelfb.txt @@ -0,0 +1,135 @@ +Intel 830M/845G/852GM/855GM/865G/915G Framebuffer driver +================================================================ + +A. Introduction + This is a framebuffer driver for various Intel 810/815 compatible +graphics devices. These would include: + + Intel 830M + Intel 810E845G + Intel 852GM + Intel 855GM + Intel 865G + Intel 915G + +B. List of available options + + a. "video=intelfb" + enables the intelfb driver + + Recommendation: required + + b. "mode=x[-][@]" + select mode + + Recommendation: user preference + (default = 1024x768-32@70) + + c. "vram=" + select amount of system RAM in MB to allocate for the video memory + if not enough RAM was already allocated by the BIOS. + + Recommendation: 1 - 4 MB. + (default = 4 MB) + + d. "voffset=" + select at what offset in MB of the logical memory to allocate the + framebuffer memory. The intent is to avoid the memory blocks + used by standard graphics applications (XFree86). Depending on your + usage, adjust the value up or down, (0 for maximum usage, 63/127 MB + for the least amount). Note, an arbitrary setting may conflict + with XFree86. + + Recommendation: do not set + (default = 48 MB) + + e. "accel" + enable text acceleration. This can be enabled/reenabled anytime + by using 'fbset -accel true/false'. + + Recommendation: enable + (default = set) + + f. "hwcursor" + enable cursor acceleration. + + Recommendation: enable + (default = set) + + g. "mtrr" + enable MTRR. This allows data transfers to the framebuffer memory + to occur in bursts which can significantly increase performance. + Not very helpful with the intel chips because of 'shared memory'. + + Recommendation: set + (default = set) + + h. "fixed" + disable mode switching. + + Recommendation: do not set + (default = not set) + + The binary parameters can be unset with a "no" prefix, example "noaccel". + The default parameter (not named) is the mode. + +C. Kernel booting + +Separate each option/option-pair by commas (,) and the option from its value +with an equals sign (=) as in the following: + +video=i810fb:option1,option2=value2 + +Sample Usage +------------ + +In /etc/lilo.conf, add the line: + +append="video=intelfb:800x600-32@75,accel,hwcursor,vram=8" + +This will initialize the framebuffer to 800x600 at 32bpp and 75Hz. The +framebuffer will use 8 MB of System RAM. hw acceleration of text and cursor +will be enabled. + +D. Module options + + The module parameters are essentially similar to the kernel +parameters. The main difference is that you need to include a Boolean value +(1 for TRUE, and 0 for FALSE) for those options which don't need a value. + +Example, to enable MTRR, include "mtrr=1". + +Sample Usage +------------ + +Using the same setup as described above, load the module like this: + + modprobe intelfb mode=800x600-32@75 vram=8 accel=1 hwcursor=1 + +Or just add the following to /etc/modprobe.conf + + options intelfb mode=800x600-32@75 vram=8 accel=1 hwcursor=1 + +and just do a + + modprobe intelfb + + +E. Acknowledgment: + + 1. Geert Uytterhoeven - his excellent howto and the virtual + framebuffer driver code made this possible. + + 2. Jeff Hartmann for his agpgart code. + + 3. David Dawes for his original kernel 2.4 code. + + 4. The X developers. Insights were provided just by reading the + XFree86 source code. + + 5. Antonino A. Daplas for his inspiring i810fb driver. + + 6. Andrew Morton for his kernel patches maintenance. + +########################### +Sylvain -- cgit v0.10.2 From 1154ea7dcd8eed758fb5ec47393a79d5a1f0bc43 Mon Sep 17 00:00:00 2001 From: Jaya Kumar Date: Tue, 21 Jun 2005 17:17:04 -0700 Subject: [PATCH] Framebuffer driver for Arc LCD board Add support for the Arc monochrome LCD board. The board uses KS108 controllers to drive individual 64x64 LCD matrices. The board can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and so on. The board/host interface is through GPIO. Signed-off-by: Jaya Kumar Cc: "Antonino A. Daplas" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/CREDITS b/CREDITS index d65ffe5..2993348 100644 --- a/CREDITS +++ b/CREDITS @@ -1880,6 +1880,13 @@ S: Schlehenweg 9 S: D-91080 Uttenreuth S: Germany +N: Jaya Kumar +E: jayalk@intworks.biz +W: http://www.intworks.biz +D: Arc monochrome LCD framebuffer driver, x86 reboot fixups +S: Gurgaon, India +S: Kuala Lumpur, Malaysia + N: Gabor Kuti M: seasons@falcon.sch.bme.hu M: seasons@makosteszta.sote.hu diff --git a/MAINTAINERS b/MAINTAINERS index e3f0f3f..0f88a70 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -265,6 +265,11 @@ P: Arnaldo Carvalho de Melo M: acme@conectiva.com.br S: Maintained +ARC FRAMEBUFFER DRIVER +P: Jaya Kumar +M: jayalk@intworks.biz +S: Maintained + ARM26 ARCHITECTURE P: Ian Molton M: spyro@f2s.com diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6be8fbe..04d3120 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -322,6 +322,22 @@ config FB_FM2 This is the frame buffer device driver for the Amiga FrameMaster card from BSC (exhibited 1992 but not shipped as a CBM product). +config FB_ARC + tristate "Arc Monochrome LCD board support" + depends on FB && X86 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + help + This enables support for the Arc Monochrome LCD board. The board + is based on the KS-108 lcd controller and is typically a matrix + of 2*n chips. This driver was tested with a 128x64 panel. This + driver supports it for use with x86 SBCs through a 16 bit GPIO + interface (8 bit data, 8 bit control). If you anticpate using + this driver, say Y or M; otherwise say N. You must specify the + GPIO IO address to be used for setting control and data. + config FB_ATARI bool "Atari native chipset support" depends on (FB = y) && ATARI && BROKEN diff --git a/drivers/video/Makefile b/drivers/video/Makefile index bd8dc0f..b018df4 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_FB_MACMODES) += macmodes.o # Hardware specific drivers go first obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o +obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o obj-$(CONFIG_FB_CYBER) += cyberfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c new file mode 100644 index 0000000..d28457e --- /dev/null +++ b/drivers/video/arcfb.c @@ -0,0 +1,684 @@ +/* + * linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board + * + * Copyright (C) 2005, Jaya Kumar + * http://www.intworks.biz/arclcd + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. + * + * This driver was written to be used with the Arc LCD board. Arc uses a + * set of KS108 chips that control individual 64x64 LCD matrices. The board + * can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and + * so on. The interface between the board and the host is TTL based GPIO. The + * GPIO requirements are 8 writable data lines and 4+n lines for control. On a + * GPIO-less system, the board can be tested by connecting the respective sigs + * up to a parallel port connector. The driver requires the IO addresses for + * data and control GPIO at load time. It is unable to probe for the + * existence of the LCD so it must be told at load time whether it should + * be enabled or not. + * + * Todo: + * - testing with 4x4 + * - testing with interrupt hw + * + * General notes: + * - User must set tuhold. It's in microseconds. According to the 108 spec, + * the hold time is supposed to be at least 1 microsecond. + * - User must set num_cols=x num_rows=y, eg: x=2 means 128 + * - User must set arcfb_enable=1 to enable it + * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define floor8(a) (a&(~0x07)) +#define floorXres(a,xres) (a&(~(xres - 1))) +#define iceil8(a) (((int)((a+7)/8))*8) +#define ceil64(a) (a|0x3F) +#define ceilXres(a,xres) (a|(xres - 1)) + +/* ks108 chipset specific defines and code */ + +#define KS_SET_DPY_START_LINE 0xC0 +#define KS_SET_PAGE_NUM 0xB8 +#define KS_SET_X 0x40 +#define KS_CEHI 0x01 +#define KS_CELO 0x00 +#define KS_SEL_CMD 0x08 +#define KS_SEL_DATA 0x00 +#define KS_DPY_ON 0x3F +#define KS_DPY_OFF 0x3E +#define KS_INTACK 0x40 +#define KS_CLRINT 0x02 + +struct arcfb_par { + unsigned long dio_addr; + unsigned long cio_addr; + unsigned long c2io_addr; + atomic_t ref_count; + unsigned char cslut[9]; + struct fb_info *info; + unsigned int irq; + spinlock_t lock; +}; + +static struct fb_fix_screeninfo arcfb_fix __initdata = { + .id = "arcfb", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_MONO01, + .xpanstep = 0, + .ypanstep = 1, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo arcfb_var __initdata = { + .xres = 128, + .yres = 64, + .xres_virtual = 128, + .yres_virtual = 64, + .bits_per_pixel = 1, + .nonstd = 1, +}; + +static unsigned long num_cols; +static unsigned long num_rows; +static unsigned long dio_addr; +static unsigned long cio_addr; +static unsigned long c2io_addr; +static unsigned long splashval; +static unsigned long tuhold; +static unsigned int nosplash; +static unsigned int arcfb_enable; +static unsigned int irq; + +static DECLARE_WAIT_QUEUE_HEAD(arcfb_waitq); + +static void ks108_writeb_ctl(struct arcfb_par *par, + unsigned int chipindex, unsigned char value) +{ + unsigned char chipselval = par->cslut[chipindex]; + + outb(chipselval|KS_CEHI|KS_SEL_CMD, par->cio_addr); + outb(value, par->dio_addr); + udelay(tuhold); + outb(chipselval|KS_CELO|KS_SEL_CMD, par->cio_addr); +} + +static void ks108_writeb_mainctl(struct arcfb_par *par, unsigned char value) +{ + + outb(value, par->cio_addr); + udelay(tuhold); +} + +static unsigned char ks108_readb_ctl2(struct arcfb_par *par) +{ + return inb(par->c2io_addr); +} + +static void ks108_writeb_data(struct arcfb_par *par, + unsigned int chipindex, unsigned char value) +{ + unsigned char chipselval = par->cslut[chipindex]; + + outb(chipselval|KS_CEHI|KS_SEL_DATA, par->cio_addr); + outb(value, par->dio_addr); + udelay(tuhold); + outb(chipselval|KS_CELO|KS_SEL_DATA, par->cio_addr); +} + +static void ks108_set_start_line(struct arcfb_par *par, + unsigned int chipindex, unsigned char y) +{ + ks108_writeb_ctl(par, chipindex, KS_SET_DPY_START_LINE|y); +} + +static void ks108_set_yaddr(struct arcfb_par *par, + unsigned int chipindex, unsigned char y) +{ + ks108_writeb_ctl(par, chipindex, KS_SET_PAGE_NUM|y); +} + +static void ks108_set_xaddr(struct arcfb_par *par, + unsigned int chipindex, unsigned char x) +{ + ks108_writeb_ctl(par, chipindex, KS_SET_X|x); +} + +static void ks108_clear_lcd(struct arcfb_par *par, unsigned int chipindex) +{ + int i,j; + + for (i = 0; i <= 8; i++) { + ks108_set_yaddr(par, chipindex, i); + ks108_set_xaddr(par, chipindex, 0); + for (j = 0; j < 64; j++) { + ks108_writeb_data(par, chipindex, + (unsigned char) splashval); + } + } +} + +/* main arcfb functions */ + +static int arcfb_open(struct fb_info *info, int user) +{ + struct arcfb_par *par = info->par; + + atomic_inc(&par->ref_count); + return 0; +} + +static int arcfb_release(struct fb_info *info, int user) +{ + struct arcfb_par *par = info->par; + int count = atomic_read(&par->ref_count); + + if (!count) + return -EINVAL; + atomic_dec(&par->ref_count); + return 0; +} + +static int arcfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int i; + struct arcfb_par *par = info->par; + + if ((var->vmode & FB_VMODE_YWRAP) && (var->yoffset < 64) + && (info->var.yres <= 64)) { + for (i = 0; i < num_cols; i++) { + ks108_set_start_line(par, i, var->yoffset); + } + info->var.yoffset = var->yoffset; + return 0; + } + + return -EINVAL; +} + +static irqreturn_t arcfb_interrupt(int vec, void *dev_instance, + struct pt_regs *regs) +{ + struct fb_info *info = dev_instance; + unsigned char ctl2status; + struct arcfb_par *par = info->par; + + ctl2status = ks108_readb_ctl2(par); + + if (!(ctl2status & KS_INTACK)) /* not arc generated interrupt */ + return IRQ_NONE; + + ks108_writeb_mainctl(par, KS_CLRINT); + + spin_lock(&par->lock); + if (waitqueue_active(&arcfb_waitq)) { + wake_up(&arcfb_waitq); + } + spin_unlock(&par->lock); + + return IRQ_HANDLED; +} + +/* + * here we handle a specific page on the lcd. the complexity comes from + * the fact that the fb is laidout in 8xX vertical columns. we extract + * each write of 8 vertical pixels. then we shift out as we move along + * X. That's what rightshift does. bitmask selects the desired input bit. + */ +static void arcfb_lcd_update_page(struct arcfb_par *par, unsigned int upper, + unsigned int left, unsigned int right, unsigned int distance) +{ + unsigned char *src; + unsigned int xindex, yindex, chipindex, linesize; + int i, count; + unsigned char val; + unsigned char bitmask, rightshift; + + xindex = left >> 6; + yindex = upper >> 6; + chipindex = (xindex + (yindex*num_cols)); + + ks108_set_yaddr(par, chipindex, upper/8); + + linesize = par->info->var.xres/8; + src = par->info->screen_base + (left/8) + (upper * linesize); + ks108_set_xaddr(par, chipindex, left); + + bitmask=1; + rightshift=0; + while (left <= right) { + val = 0; + for (i = 0; i < 8; i++) { + if ( i > rightshift) { + val |= (*(src + (i*linesize)) & bitmask) + << (i - rightshift); + } else { + val |= (*(src + (i*linesize)) & bitmask) + >> (rightshift - i); + } + } + ks108_writeb_data(par, chipindex, val); + left++; + count++; + if (bitmask == 0x80) { + bitmask = 1; + src++; + rightshift=0; + } else { + bitmask <<= 1; + rightshift++; + } + } +} + +/* + * here we handle the entire vertical page of the update. we write across + * lcd chips. update_page uses the upper/left values to decide which + * chip to select for the right. upper is needed for setting the page + * desired for the write. + */ +static void arcfb_lcd_update_vert(struct arcfb_par *par, unsigned int top, + unsigned int bottom, unsigned int left, unsigned int right) +{ + unsigned int distance, upper, lower; + + distance = (bottom - top) + 1; + upper = top; + lower = top + 7; + + while (distance > 0) { + distance -= 8; + arcfb_lcd_update_page(par, upper, left, right, 8); + upper = lower + 1; + lower = upper + 7; + } +} + +/* + * here we handle horizontal blocks for the update. update_vert will + * handle spaning multiple pages. we break out each horizontal + * block in to individual blocks no taller than 64 pixels. + */ +static void arcfb_lcd_update_horiz(struct arcfb_par *par, unsigned int left, + unsigned int right, unsigned int top, unsigned int h) +{ + unsigned int distance, upper, lower; + + distance = h; + upper = floor8(top); + lower = min(upper + distance - 1, ceil64(upper)); + + while (distance > 0) { + distance -= ((lower - upper) + 1 ); + arcfb_lcd_update_vert(par, upper, lower, left, right); + upper = lower + 1; + lower = min(upper + distance - 1, ceil64(upper)); + } +} + +/* + * here we start the process of spliting out the fb update into + * individual blocks of pixels. we end up spliting into 64x64 blocks + * and finally down to 64x8 pages. + */ +static void arcfb_lcd_update(struct arcfb_par *par, unsigned int dx, + unsigned int dy, unsigned int w, unsigned int h) +{ + unsigned int left, right, distance, y; + + /* align the request first */ + y = floor8(dy); + h += dy - y; + h = iceil8(h); + + distance = w; + left = dx; + right = min(left + w - 1, ceil64(left)); + + while (distance > 0) { + arcfb_lcd_update_horiz(par, left, right, y, h); + distance -= ((right - left) + 1); + left = right + 1; + right = min(left + distance - 1, ceil64(left)); + } +} + +void arcfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct arcfb_par *par = info->par; + + cfb_fillrect(info, rect); + + /* update the physical lcd */ + arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height); +} + +void arcfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct arcfb_par *par = info->par; + + cfb_copyarea(info, area); + + /* update the physical lcd */ + arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height); +} + +void arcfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct arcfb_par *par = info->par; + + cfb_imageblit(info, image); + + /* update the physical lcd */ + arcfb_lcd_update(par, image->dx, image->dy, image->width, + image->height); +} + +static int arcfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info) +{ + void __user *argp = (void __user *)arg; + struct arcfb_par *par = info->par; + unsigned long flags; + + switch (cmd) { + case FBIO_WAITEVENT: + { + DEFINE_WAIT(wait); + /* illegal to wait on arc if no irq will occur */ + if (!par->irq) + return -EINVAL; + + /* wait until the Arc has generated an interrupt + * which will wake us up */ + spin_lock_irqsave(&par->lock, flags); + prepare_to_wait(&arcfb_waitq, &wait, + TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&par->lock, flags); + schedule(); + finish_wait(&arcfb_waitq, &wait); + } + case FBIO_GETCONTROL2: + { + unsigned char ctl2; + + ctl2 = ks108_readb_ctl2(info->par); + if (copy_to_user(argp, &ctl2, sizeof(ctl2))) + return -EFAULT; + return 0; + } + default: + return -EINVAL; + } +} + +/* + * this is the access path from userspace. they can seek and write to + * the fb. it's inefficient for them to do anything less than 64*8 + * writes since we update the lcd in each write() anyway. + */ +static ssize_t arcfb_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) +{ + /* modded from epson 1355 */ + + struct inode *inode; + int fbidx; + struct fb_info *info; + unsigned long p; + int err=-EINVAL; + unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount; + struct arcfb_par *par; + unsigned int xres; + + p = *ppos; + inode = file->f_dentry->d_inode; + fbidx = iminor(inode); + info = registered_fb[fbidx]; + par = info->par; + + if (!info || !info->screen_base) + return -ENODEV; + + xres = info->var.xres; + fbmemlength = (xres * info->var.yres)/8; + + if (p > fbmemlength) + return -ENOSPC; + + err = 0; + if ((count + p) > fbmemlength) { + count = fbmemlength - p; + err = -ENOSPC; + } + + if (count) { + char *base_addr; + + base_addr = info->screen_base; + count -= copy_from_user(base_addr + p, buf, count); + *ppos += count; + err = -EFAULT; + } + + + bitppos = p*8; + startpos = floorXres(bitppos, xres); + endpos = ceilXres((bitppos + (count*8)), xres); + bitcount = endpos - startpos; + + x = startpos % xres; + y = startpos / xres; + w = xres; + h = bitcount / xres; + arcfb_lcd_update(par, x, y, w, h); + + if (count) + return count; + return err; +} + +static void arcfb_platform_release(struct device *device) +{ +} + +static struct fb_ops arcfb_ops = { + .owner = THIS_MODULE, + .fb_open = arcfb_open, + .fb_write = arcfb_write, + .fb_release = arcfb_release, + .fb_pan_display = arcfb_pan_display, + .fb_fillrect = arcfb_fillrect, + .fb_copyarea = arcfb_copyarea, + .fb_imageblit = arcfb_imageblit, + .fb_cursor = soft_cursor, + .fb_ioctl = arcfb_ioctl, +}; + +static int __init arcfb_probe(struct device *device) +{ + struct platform_device *dev = to_platform_device(device); + struct fb_info *info; + int retval = -ENOMEM; + int videomemorysize; + unsigned char *videomemory; + struct arcfb_par *par; + int i; + + videomemorysize = (((64*64)*num_cols)*num_rows)/8; + + /* We need a flat backing store for the Arc's + less-flat actual paged framebuffer */ + if (!(videomemory = vmalloc(videomemorysize))) + return retval; + + memset(videomemory, 0, videomemorysize); + + info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev); + if (!info) + goto err; + + info->screen_base = (char __iomem *)videomemory; + info->fbops = &arcfb_ops; + + info->var = arcfb_var; + info->fix = arcfb_fix; + par = info->par; + par->info = info; + + if (!dio_addr || !cio_addr || !c2io_addr) { + printk(KERN_WARNING "no IO addresses supplied\n"); + goto err1; + } + par->dio_addr = dio_addr; + par->cio_addr = cio_addr; + par->c2io_addr = c2io_addr; + par->cslut[0] = 0x00; + par->cslut[1] = 0x06; + info->flags = FBINFO_FLAG_DEFAULT; + spin_lock_init(&par->lock); + retval = register_framebuffer(info); + if (retval < 0) + goto err1; + dev_set_drvdata(&dev->dev, info); + if (irq) { + par->irq = irq; + if (request_irq(par->irq, &arcfb_interrupt, SA_SHIRQ, + "arcfb", info)) { + printk(KERN_INFO + "arcfb: Failed req IRQ %d\n", par->irq); + goto err1; + } + } + printk(KERN_INFO + "fb%d: Arc frame buffer device, using %dK of video memory\n", + info->node, videomemorysize >> 10); + + /* this inits the lcd but doesn't clear dirty pixels */ + for (i = 0; i < num_cols * num_rows; i++) { + ks108_writeb_ctl(par, i, KS_DPY_OFF); + ks108_set_start_line(par, i, 0); + ks108_set_yaddr(par, i, 0); + ks108_set_xaddr(par, i, 0); + ks108_writeb_ctl(par, i, KS_DPY_ON); + } + + /* if we were told to splash the screen, we just clear it */ + if (!nosplash) { + for (i = 0; i < num_cols * num_rows; i++) { + printk(KERN_INFO "fb%d: splashing lcd %d\n", + info->node, i); + ks108_set_start_line(par, i, 0); + ks108_clear_lcd(par, i); + } + } + + return 0; +err1: + framebuffer_release(info); +err: + vfree(videomemory); + return retval; +} + +static int arcfb_remove(struct device *device) +{ + struct fb_info *info = dev_get_drvdata(device); + + if (info) { + unregister_framebuffer(info); + vfree(info->screen_base); + framebuffer_release(info); + } + return 0; +} + +static struct device_driver arcfb_driver = { + .name = "arcfb", + .bus = &platform_bus_type, + .probe = arcfb_probe, + .remove = arcfb_remove, +}; + +static struct platform_device arcfb_device = { + .name = "arcfb", + .id = 0, + .dev = { + .release = arcfb_platform_release, + } +}; + +static int __init arcfb_init(void) +{ + int ret; + + if (!arcfb_enable) + return -ENXIO; + + ret = driver_register(&arcfb_driver); + if (!ret) { + ret = platform_device_register(&arcfb_device); + if (ret) + driver_unregister(&arcfb_driver); + } + return ret; + +} + +static void __exit arcfb_exit(void) +{ + platform_device_unregister(&arcfb_device); + driver_unregister(&arcfb_driver); +} + +module_param(num_cols, ulong, 0); +MODULE_PARM_DESC(num_cols, "Num horiz panels, eg: 2 = 128 bit wide"); +module_param(num_rows, ulong, 0); +MODULE_PARM_DESC(num_rows, "Num vert panels, eg: 1 = 64 bit high"); +module_param(nosplash, uint, 0); +MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); +module_param(arcfb_enable, uint, 0); +MODULE_PARM_DESC(arcfb_enable, "Enable communication with Arc board"); +module_param(dio_addr, ulong, 0); +MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); +module_param(cio_addr, ulong, 0); +MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); +module_param(c2io_addr, ulong, 0); +MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); +module_param(splashval, ulong, 0); +MODULE_PARM_DESC(splashval, "Splash pattern: 0xFF is black, 0x00 is green"); +module_param(tuhold, ulong, 0); +MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Arc board"); +module_param(irq, uint, 0); +MODULE_PARM_DESC(irq, "IRQ for the Arc board"); + +module_init(arcfb_init); +module_exit(arcfb_exit); + +MODULE_DESCRIPTION("fbdev driver for Arc monochrome LCD board"); +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); + diff --git a/include/linux/arcfb.h b/include/linux/arcfb.h new file mode 100644 index 0000000..721e765 --- /dev/null +++ b/include/linux/arcfb.h @@ -0,0 +1,8 @@ +#ifndef __LINUX_ARCFB_H__ +#define __LINUX_ARCFB_H__ + +#define FBIO_WAITEVENT _IO('F', 0x88) +#define FBIO_GETCONTROL2 _IOR('F', 0x89, size_t) + +#endif + -- cgit v0.10.2 From d5881eb4883ef7dd28a4dcea237714817c4b2f8e Mon Sep 17 00:00:00 2001 From: James Simmons Date: Tue, 21 Jun 2005 17:17:05 -0700 Subject: [PATCH] fbdev: new pci id for chipsfb Patch adds pci ID for CT 69000 chipset. Signed-off-by: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index b8b4ebf..63e89e4 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -575,6 +575,7 @@ #define PCI_DEVICE_ID_CT_65550 0x00e0 #define PCI_DEVICE_ID_CT_65554 0x00e4 #define PCI_DEVICE_ID_CT_65555 0x00e5 +#define PCI_DEVICE_ID_CT_69000 0x00c0 #define PCI_VENDOR_ID_MIRO 0x1031 #define PCI_DEVICE_ID_MIRO_36050 0x5601 -- cgit v0.10.2 From 303b86d9913eca0cbfc3c5cb41e7006f6e13b755 Mon Sep 17 00:00:00 2001 From: Jurriaan Date: Tue, 21 Jun 2005 17:17:06 -0700 Subject: [PATCH] New framebuffer fonts + updated 12x22 font available Improve the fonts for use with the framebuffer. I've added all the characters marked 'FIXME' in the sun12x22 font and created a 10x18 font (based on the sun12x22 font) and a 7x14 font (based on the vga8x16 font). This patch is non-intrusive, no options are enabled by default so most users won't notice a thing. I am placing my changes under the GPL, however, I've not seen any copyright notices on the sun12x22 font and the vga8x16 font which I derived my new fonts from so I don't know what the copyright status is. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index ccf5581..e4b91a4 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -153,6 +153,15 @@ config FONT_6x11 Small console font with Macintosh-style high-half glyphs. Some Mac framebuffer drivers don't support this one at all. +config FONT_7x14 + bool "console 7x14 font (not supported by all drivers)" if FONTS + depends on FRAMEBUFFER_CONSOLE + default y if !SPARC32 && !SPARC64 && !FONTS + help + Console font with characters just a bit smaller than the default. + If the standard 8x16 font is a little too big for you, say Y. + Otherwise, say N. + config FONT_PEARL_8x8 bool "Pearl (old m68k) console 8x8 font" if FONTS depends on FRAMEBUFFER_CONSOLE @@ -187,5 +196,13 @@ config FONT_SUN12x22 big letters (like the letters used in the SPARC PROM). If the standard font is unreadable for you, say Y, otherwise say N. +config FONT_10x18 + bool "console 10x18 font (not supported by all drivers)" + depends on FONTS + help + This is a high resolution console font for machines with very + big letters. It fits between the sun 12x22 and the normal 8x16 font. + If other fonts are too big or too small for you, say Y, otherwise say N. + endmenu diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index 3351644..b562f6b 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile @@ -10,6 +10,8 @@ font-objs-$(CONFIG_FONT_SUN12x22) += font_sun12x22.o font-objs-$(CONFIG_FONT_8x8) += font_8x8.o font-objs-$(CONFIG_FONT_8x16) += font_8x16.o font-objs-$(CONFIG_FONT_6x11) += font_6x11.o +font-objs-$(CONFIG_FONT_7x14) += font_7x14.o +font-objs-$(CONFIG_FONT_10x18) += font_10x18.o font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o diff --git a/drivers/video/console/font_10x18.c b/drivers/video/console/font_10x18.c new file mode 100644 index 0000000..ff0af96 --- /dev/null +++ b/drivers/video/console/font_10x18.c @@ -0,0 +1,5146 @@ +/******************************** + * adapted from font_sun12x22.c * + * by Jurriaan Kalkman 06-2005 * + ********************************/ + +#include + +#define FONTDATAMAX 9216 + +static unsigned char fontdata_10x18[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 1 0x01 '^A' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3f, 0x80, /* 0011111110 */ + 0x40, 0x40, /* 0100000001 */ + 0x5b, 0x40, /* 0101101101 */ + 0x40, 0x40, /* 0100000001 */ + 0x44, 0x40, /* 0100010001 */ + 0x44, 0x40, /* 0100010001 */ + 0x51, 0x40, /* 0101000101 */ + 0x4e, 0x40, /* 0100111001 */ + 0x40, 0x40, /* 0100000001 */ + 0x3f, 0x80, /* 0011111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 2 0x02 '^B' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3f, 0x80, /* 0011111110 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x64, 0xc0, /* 0110010011 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x7b, 0xc0, /* 0111101111 */ + 0x7b, 0xc0, /* 0111101111 */ + 0x6e, 0xc0, /* 0110111011 */ + 0x71, 0xc0, /* 0111000111 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x3f, 0x80, /* 0011111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 3 0x03 '^C' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x11, 0x00, /* 0001000100 */ + 0x3b, 0x80, /* 0011101110 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x3f, 0x80, /* 0011111110 */ + 0x3f, 0x80, /* 0011111110 */ + 0x1f, 0x00, /* 0001111100 */ + 0x1f, 0x00, /* 0001111100 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x04, 0x00, /* 0000010000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 4 0x04 '^D' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x04, 0x00, /* 0000010000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x1f, 0x00, /* 0001111100 */ + 0x3f, 0x80, /* 0011111110 */ + 0x1f, 0x00, /* 0001111100 */ + 0x1f, 0x00, /* 0001111100 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x04, 0x00, /* 0000010000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 5 0x05 '^E' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x31, 0x80, /* 0011000110 */ + 0x7b, 0xc0, /* 0111101111 */ + 0x35, 0x80, /* 0011010110 */ + 0x04, 0x00, /* 0000010000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 6 0x06 '^F' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x04, 0x00, /* 0000010000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x1f, 0x00, /* 0001111100 */ + 0x3f, 0x80, /* 0011111110 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x35, 0x80, /* 0011010110 */ + 0x04, 0x00, /* 0000010000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 7 0x07 '^G' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 8 0x08 '^H' */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xf3, 0xc0, /* 1111001111 */ + 0xe1, 0xc0, /* 1110000111 */ + 0xe1, 0xc0, /* 1110000111 */ + 0xc0, 0xc0, /* 1100000011 */ + 0xc0, 0xc0, /* 1100000011 */ + 0xe1, 0xc0, /* 1110000111 */ + 0xe1, 0xc0, /* 1110000111 */ + 0xf3, 0xc0, /* 1111001111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + + /* 9 0x09 '^I' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x12, 0x00, /* 0001001000 */ + 0x12, 0x00, /* 0001001000 */ + 0x21, 0x00, /* 0010000100 */ + 0x21, 0x00, /* 0010000100 */ + 0x12, 0x00, /* 0001001000 */ + 0x12, 0x00, /* 0001001000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 10 0x0a '^J' */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xf3, 0xc0, /* 1111001111 */ + 0xed, 0xc0, /* 1110110111 */ + 0xed, 0xc0, /* 1110110111 */ + 0xde, 0xc0, /* 1101111011 */ + 0xde, 0xc0, /* 1101111011 */ + 0xed, 0xc0, /* 1110110111 */ + 0xed, 0xc0, /* 1110110111 */ + 0xf3, 0xc0, /* 1111001111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + + /* 11 0x0b '^K' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x03, 0xc0, /* 0000001111 */ + 0x06, 0xc0, /* 0000011011 */ + 0x0c, 0xc0, /* 0000110011 */ + 0x3c, 0x00, /* 0011110000 */ + 0x66, 0x00, /* 0110011000 */ + 0xc3, 0x00, /* 1100001100 */ + 0xc3, 0x00, /* 1100001100 */ + 0xc3, 0x00, /* 1100001100 */ + 0x66, 0x00, /* 0110011000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 12 0x0c '^L' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x33, 0x00, /* 0011001100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 13 0x0d '^M' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0f, 0x80, /* 0000111110 */ + 0x08, 0x80, /* 0000100010 */ + 0x0f, 0x80, /* 0000111110 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x38, 0x00, /* 0011100000 */ + 0x78, 0x00, /* 0111100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 14 0x0e '^N' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x80, /* 0001111110 */ + 0x10, 0x80, /* 0001000010 */ + 0x1f, 0x80, /* 0001111110 */ + 0x10, 0x80, /* 0001000010 */ + 0x10, 0x80, /* 0001000010 */ + 0x10, 0x80, /* 0001000010 */ + 0x10, 0x80, /* 0001000010 */ + 0x13, 0x80, /* 0001001110 */ + 0x17, 0x80, /* 0001011110 */ + 0x73, 0x00, /* 0111001100 */ + 0xf0, 0x00, /* 1111000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 15 0x0f '^O' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x04, 0x00, /* 0000010000 */ + 0x24, 0x80, /* 0010010010 */ + 0x15, 0x00, /* 0001010100 */ + 0x55, 0x40, /* 0101010101 */ + 0x3f, 0x80, /* 0011111110 */ + 0x0e, 0x00, /* 0000111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x3f, 0x80, /* 0011111110 */ + 0x55, 0x40, /* 0101010101 */ + 0x15, 0x00, /* 0001010100 */ + 0x24, 0x80, /* 0010010010 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 16 0x10 '^P' */ + 0x00, 0x80, /* 0000000010 */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0x80, /* 0000001110 */ + 0x07, 0x80, /* 0000011110 */ + 0x0f, 0x80, /* 0000111110 */ + 0x1f, 0x80, /* 0001111110 */ + 0x3f, 0x80, /* 0011111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0xff, 0x80, /* 1111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x3f, 0x80, /* 0011111110 */ + 0x1f, 0x80, /* 0001111110 */ + 0x0f, 0x80, /* 0000111110 */ + 0x07, 0x80, /* 0000011110 */ + 0x03, 0x80, /* 0000001110 */ + 0x01, 0x80, /* 0000000110 */ + 0x00, 0x80, /* 0000000010 */ + 0x00, 0x00, /* 0000000000 */ + + /* 17 0x11 '^Q' */ + 0x40, 0x00, /* 0100000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x70, 0x00, /* 0111000000 */ + 0x78, 0x00, /* 0111100000 */ + 0x7c, 0x00, /* 0111110000 */ + 0x7e, 0x00, /* 0111111000 */ + 0x7f, 0x00, /* 0111111100 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x00, /* 0111111100 */ + 0x7e, 0x00, /* 0111111000 */ + 0x7c, 0x00, /* 0111110000 */ + 0x78, 0x00, /* 0111100000 */ + 0x70, 0x00, /* 0111000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x40, 0x00, /* 0100000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 18 0x12 '^R' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x7f, 0x80, /* 0111111110 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x3f, 0x00, /* 0011111100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 19 0x13 '^S' */ + 0x00, 0x00, /* 0000000000 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 20 0x14 '^T' */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0xc0, /* 0001111111 */ + 0x39, 0x80, /* 0011100110 */ + 0x79, 0x80, /* 0111100110 */ + 0x79, 0x80, /* 0111100110 */ + 0x79, 0x80, /* 0111100110 */ + 0x39, 0x80, /* 0011100110 */ + 0x19, 0x80, /* 0001100110 */ + 0x19, 0x80, /* 0001100110 */ + 0x19, 0x80, /* 0001100110 */ + 0x19, 0x80, /* 0001100110 */ + 0x19, 0x80, /* 0001100110 */ + 0x19, 0x80, /* 0001100110 */ + 0x39, 0xc0, /* 0011100111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 21 0x15 '^U' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x3e, 0x00, /* 0011111000 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x3e, 0x00, /* 0011111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 22 0x16 '^V' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 23 0x17 '^W' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x7f, 0x80, /* 0111111110 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x3f, 0x00, /* 0011111100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 24 0x18 '^X' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x7f, 0x80, /* 0111111110 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 25 0x19 '^Y' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x3f, 0x00, /* 0011111100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 26 0x1a '^Z' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x04, 0x00, /* 0000010000 */ + 0x06, 0x00, /* 0000011000 */ + 0x07, 0x00, /* 0000011100 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x07, 0x00, /* 0000011100 */ + 0x06, 0x00, /* 0000011000 */ + 0x04, 0x00, /* 0000010000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 27 0x1b '^[' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x08, 0x00, /* 0000100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x38, 0x00, /* 0011100000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x38, 0x00, /* 0011100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 28 0x1c '^\' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 29 0x1d '^]' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x12, 0x00, /* 0001001000 */ + 0x33, 0x00, /* 0011001100 */ + 0x73, 0x80, /* 0111001110 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x73, 0x80, /* 0111001110 */ + 0x33, 0x00, /* 0011001100 */ + 0x12, 0x00, /* 0001001000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 30 0x1e '^^' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x04, 0x00, /* 0000010000 */ + 0x04, 0x00, /* 0000010000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x1f, 0x00, /* 0001111100 */ + 0x3f, 0x80, /* 0011111110 */ + 0x3f, 0x80, /* 0011111110 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 31 0x1f '^_' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x3f, 0x80, /* 0011111110 */ + 0x3f, 0x80, /* 0011111110 */ + 0x1f, 0x00, /* 0001111100 */ + 0x1f, 0x00, /* 0001111100 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x04, 0x00, /* 0000010000 */ + 0x04, 0x00, /* 0000010000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 32 0x20 ' ' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 33 0x21 '!' */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 34 0x22 '"' */ + 0x00, 0x00, /* 0000000000 */ + 0x63, 0x00, /* 0110001100 */ + 0xf7, 0x80, /* 1111011110 */ + 0xf7, 0x80, /* 1111011110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x63, 0x00, /* 0110001100 */ + 0x42, 0x00, /* 0100001000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 35 0x23 '#' */ + 0x00, 0x00, /* 0000000000 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 36 0x24 '$' */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x6f, 0x80, /* 0110111110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6c, 0x80, /* 0110110010 */ + 0x3c, 0x00, /* 0011110000 */ + 0x0f, 0x00, /* 0000111100 */ + 0x0d, 0x80, /* 0000110110 */ + 0x4d, 0x80, /* 0100110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x7f, 0x00, /* 0111111100 */ + 0x3e, 0x00, /* 0011111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 37 0x25 '%' */ + 0x00, 0x00, /* 0000000000 */ + 0x31, 0x80, /* 0011000110 */ + 0x7b, 0x00, /* 0111101100 */ + 0x7b, 0x00, /* 0111101100 */ + 0x36, 0x00, /* 0011011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x1b, 0x00, /* 0001101100 */ + 0x37, 0x80, /* 0011011110 */ + 0x37, 0x80, /* 0011011110 */ + 0x63, 0x00, /* 0110001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 38 0x26 '&' */ + 0x00, 0x00, /* 0000000000 */ + 0x07, 0x00, /* 0000011100 */ + 0x0f, 0x80, /* 0000111110 */ + 0x19, 0x80, /* 0001100110 */ + 0x19, 0x80, /* 0001100110 */ + 0x0f, 0x80, /* 0000111110 */ + 0x1e, 0x00, /* 0001111000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x76, 0x00, /* 0111011000 */ + 0x66, 0x40, /* 0110011001 */ + 0x63, 0xc0, /* 0110001111 */ + 0x63, 0x80, /* 0110001110 */ + 0x63, 0x00, /* 0110001100 */ + 0x3f, 0x80, /* 0011111110 */ + 0x1c, 0xc0, /* 0001110011 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 39 0x27 ''' */ + 0x00, 0x00, /* 0000000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x78, 0x00, /* 0111100000 */ + 0x78, 0x00, /* 0111100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x20, 0x00, /* 0010000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 40 0x28 '(' */ + 0x00, 0x00, /* 0000000000 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x06, 0x00, /* 0000011000 */ + 0x03, 0x00, /* 0000001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 41 0x29 ')' */ + 0x00, 0x00, /* 0000000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 42 0x2a '*' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x4c, 0x80, /* 0100110010 */ + 0x6d, 0x80, /* 0110110110 */ + 0x3f, 0x00, /* 0011111100 */ + 0x7f, 0x80, /* 0111111110 */ + 0x3f, 0x00, /* 0011111100 */ + 0x6d, 0x80, /* 0110110110 */ + 0x4c, 0x80, /* 0100110010 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 43 0x2b '+' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 44 0x2c ',' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x78, 0x00, /* 0111100000 */ + 0x78, 0x00, /* 0111100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x40, 0x00, /* 0100000000 */ + + /* 45 0x2d '-' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 46 0x2e '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 47 0x2f '/' */ + 0x00, 0x00, /* 0000000000 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 48 0x30 '0' */ + 0x00, 0x00, /* 0000000000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x23, 0x00, /* 0010001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x63, 0x80, /* 0110001110 */ + 0x65, 0x80, /* 0110010110 */ + 0x65, 0x80, /* 0110010110 */ + 0x69, 0x80, /* 0110100110 */ + 0x69, 0x80, /* 0110100110 */ + 0x71, 0x80, /* 0111000110 */ + 0x61, 0x00, /* 0110000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x3e, 0x00, /* 0011111000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 49 0x31 '1' */ + 0x00, 0x00, /* 0000000000 */ + 0x04, 0x00, /* 0000010000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 50 0x32 '2' */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x63, 0x80, /* 0110001110 */ + 0x41, 0x80, /* 0100000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x80, /* 0011000010 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 51 0x33 '3' */ + 0x00, 0x00, /* 0000000000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x47, 0x00, /* 0100011100 */ + 0x03, 0x00, /* 0000001100 */ + 0x07, 0x00, /* 0000011100 */ + 0x06, 0x00, /* 0000011000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x07, 0x00, /* 0000011100 */ + 0x03, 0x00, /* 0000001100 */ + 0x01, 0x80, /* 0000000110 */ + 0x41, 0x80, /* 0100000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x3f, 0x00, /* 0011111100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 52 0x34 '4' */ + 0x00, 0x00, /* 0000000000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x36, 0x00, /* 0011011000 */ + 0x36, 0x00, /* 0011011000 */ + 0x66, 0x00, /* 0110011000 */ + 0x66, 0x00, /* 0110011000 */ + 0xc6, 0x00, /* 1100011000 */ + 0xc6, 0x00, /* 1100011000 */ + 0xff, 0x80, /* 1111111110 */ + 0xff, 0x80, /* 1111111110 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 53 0x35 '5' */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x1f, 0x00, /* 0001111100 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x7e, 0x00, /* 0111111000 */ + 0x67, 0x00, /* 0110011100 */ + 0x03, 0x80, /* 0000001110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x41, 0x80, /* 0100000110 */ + 0x63, 0x00, /* 0110001100 */ + 0x3e, 0x00, /* 0011111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 54 0x36 '6' */ + 0x00, 0x00, /* 0000000000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x6e, 0x00, /* 0110111000 */ + 0x7f, 0x00, /* 0111111100 */ + 0x73, 0x80, /* 0111001110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x71, 0x00, /* 0111000100 */ + 0x3e, 0x00, /* 0011111000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 55 0x37 '7' */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x80, /* 0001111110 */ + 0x3f, 0x80, /* 0011111110 */ + 0x61, 0x80, /* 0110000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 56 0x38 '8' */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x23, 0x00, /* 0010001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x31, 0x00, /* 0011000100 */ + 0x1a, 0x00, /* 0001101000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x16, 0x00, /* 0001011000 */ + 0x23, 0x00, /* 0010001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x31, 0x00, /* 0011000100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 57 0x39 '9' */ + 0x00, 0x00, /* 0000000000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x17, 0x00, /* 0001011100 */ + 0x23, 0x80, /* 0010001110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x80, /* 0111001110 */ + 0x3d, 0x80, /* 0011110110 */ + 0x19, 0x80, /* 0001100110 */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 58 0x3a ':' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 59 0x3b ';' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x20, 0x00, /* 0010000000 */ + + /* 60 0x3c '<' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x06, 0x00, /* 0000011000 */ + 0x03, 0x00, /* 0000001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 61 0x3d '=' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 62 0x3e '>' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x06, 0x00, /* 0000011000 */ + 0x03, 0x00, /* 0000001100 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 63 0x3f '?' */ + 0x00, 0x00, /* 0000000000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x3b, 0x80, /* 0011101110 */ + 0x21, 0x80, /* 0010000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 64 0x40 '@' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x31, 0x80, /* 0011000110 */ + 0x65, 0x80, /* 0110010110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6f, 0x80, /* 0110111110 */ + 0x60, 0x00, /* 0110000000 */ + 0x31, 0x80, /* 0011000110 */ + 0x3f, 0x80, /* 0011111110 */ + 0x0f, 0x00, /* 0000111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 65 0x41 'A' */ + 0x00, 0x00, /* 0000000000 */ + 0x04, 0x00, /* 0000010000 */ + 0x04, 0x00, /* 0000010000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x19, 0x80, /* 0001100110 */ + 0x31, 0x80, /* 0011000110 */ + 0x3f, 0x80, /* 0011111110 */ + 0x31, 0x80, /* 0011000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x60, 0xc0, /* 0110000011 */ + 0x60, 0xc0, /* 0110000011 */ + 0xf1, 0xc0, /* 1111000111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 66 0x42 'B' */ + 0x00, 0x00, /* 0000000000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x62, 0x00, /* 0110001000 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x66, 0x00, /* 0110011000 */ + 0x7e, 0x00, /* 0111111000 */ + 0x63, 0x00, /* 0110001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x63, 0x00, /* 0110001100 */ + 0xfe, 0x00, /* 1111111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 67 0x43 'C' */ + 0x00, 0x00, /* 0000000000 */ + 0x0f, 0x00, /* 0000111100 */ + 0x11, 0x80, /* 0001000110 */ + 0x20, 0x80, /* 0010000010 */ + 0x20, 0x00, /* 0010000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x20, 0x00, /* 0010000000 */ + 0x30, 0x80, /* 0011000010 */ + 0x19, 0x00, /* 0001100100 */ + 0x0e, 0x00, /* 0000111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 68 0x44 'D' */ + 0x00, 0x00, /* 0000000000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x67, 0x00, /* 0110011100 */ + 0x63, 0x00, /* 0110001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x00, /* 0110000100 */ + 0x66, 0x00, /* 0110011000 */ + 0xf8, 0x00, /* 1111100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 69 0x45 'E' */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x30, 0x80, /* 0011000010 */ + 0x30, 0x80, /* 0011000010 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x31, 0x00, /* 0011000100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x31, 0x00, /* 0011000100 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x80, /* 0011000010 */ + 0x30, 0x80, /* 0011000010 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 70 0x46 'F' */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x30, 0x80, /* 0011000010 */ + 0x30, 0x80, /* 0011000010 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x31, 0x00, /* 0011000100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x31, 0x00, /* 0011000100 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x78, 0x00, /* 0111100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 71 0x47 'G' */ + 0x00, 0x00, /* 0000000000 */ + 0x0f, 0x00, /* 0000111100 */ + 0x11, 0x80, /* 0001000110 */ + 0x20, 0x80, /* 0010000010 */ + 0x20, 0x00, /* 0010000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x67, 0xc0, /* 0110011111 */ + 0x61, 0x80, /* 0110000110 */ + 0x21, 0x80, /* 0010000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x19, 0x80, /* 0001100110 */ + 0x0e, 0x00, /* 0000111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 72 0x48 'H' */ + 0x00, 0x00, /* 0000000000 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 73 0x49 'I' */ + 0x00, 0x00, /* 0000000000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 74 0x4a 'J' */ + 0x00, 0x00, /* 0000000000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x08, 0x00, /* 0000100000 */ + 0x70, 0x00, /* 0111000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 75 0x4b 'K' */ + 0x00, 0x00, /* 0000000000 */ + 0xf1, 0x80, /* 1111000110 */ + 0x63, 0x00, /* 0110001100 */ + 0x66, 0x00, /* 0110011000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x78, 0x00, /* 0111100000 */ + 0x70, 0x00, /* 0111000000 */ + 0x70, 0x00, /* 0111000000 */ + 0x78, 0x00, /* 0111100000 */ + 0x78, 0x00, /* 0111100000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x66, 0x00, /* 0110011000 */ + 0x63, 0x00, /* 0110001100 */ + 0x61, 0x80, /* 0110000110 */ + 0xf0, 0xc0, /* 1111000011 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 76 0x4c 'L' */ + 0x00, 0x00, /* 0000000000 */ + 0x78, 0x00, /* 0111100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x80, /* 0011000010 */ + 0x30, 0x80, /* 0011000010 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 77 0x4d 'M' */ + 0x00, 0x00, /* 0000000000 */ + 0xe0, 0xc0, /* 1110000011 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x80, /* 0111001110 */ + 0x73, 0x80, /* 0111001110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 78 0x4e 'N' */ + 0x00, 0x00, /* 0000000000 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x71, 0x80, /* 0111000110 */ + 0x79, 0x80, /* 0111100110 */ + 0x79, 0x80, /* 0111100110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x67, 0x80, /* 0110011110 */ + 0x67, 0x80, /* 0110011110 */ + 0x63, 0x80, /* 0110001110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 79 0x4f 'O' */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x17, 0x00, /* 0001011100 */ + 0x23, 0x00, /* 0010001100 */ + 0x21, 0x80, /* 0010000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x21, 0x00, /* 0010000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x1a, 0x00, /* 0001101000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 80 0x50 'P' */ + 0x00, 0x00, /* 0000000000 */ + 0xfe, 0x00, /* 1111111000 */ + 0x63, 0x00, /* 0110001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x63, 0x00, /* 0110001100 */ + 0x7e, 0x00, /* 0111111000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0xf0, 0x00, /* 1111000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 81 0x51 'Q' */ + 0x00, 0x00, /* 0000000000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x13, 0x00, /* 0001001100 */ + 0x23, 0x00, /* 0010001100 */ + 0x21, 0x80, /* 0010000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x3b, 0x00, /* 0011101100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x26, 0x00, /* 0010011000 */ + 0x03, 0x80, /* 0000001110 */ + 0x00, 0x00, /* 0000000000 */ + + /* 82 0x52 'R' */ + 0x00, 0x00, /* 0000000000 */ + 0xfe, 0x00, /* 1111111000 */ + 0x63, 0x00, /* 0110001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x00, /* 0110000100 */ + 0x7e, 0x00, /* 0111111000 */ + 0x78, 0x00, /* 0111100000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x6e, 0x00, /* 0110111000 */ + 0x67, 0x00, /* 0110011100 */ + 0x63, 0x80, /* 0110001110 */ + 0x61, 0xc0, /* 0110000111 */ + 0xf0, 0xc0, /* 1111000011 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 83 0x53 'S' */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x31, 0x80, /* 0011000110 */ + 0x60, 0x80, /* 0110000010 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x06, 0x00, /* 0000011000 */ + 0x03, 0x00, /* 0000001100 */ + 0x01, 0x80, /* 0000000110 */ + 0x41, 0x80, /* 0100000110 */ + 0x63, 0x00, /* 0110001100 */ + 0x3e, 0x00, /* 0011111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 84 0x54 'T' */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x4c, 0x80, /* 0100110010 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 85 0x55 'U' */ + 0x00, 0x00, /* 0000000000 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x00, /* 0111001100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 86 0x56 'V' */ + 0x00, 0x00, /* 0000000000 */ + 0xe1, 0xc0, /* 1110000111 */ + 0xc0, 0xc0, /* 1100000011 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x12, 0x00, /* 0001001000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 87 0x57 'W' */ + 0x00, 0x00, /* 0000000000 */ + 0xe1, 0xc0, /* 1110000111 */ + 0xc0, 0xc0, /* 1100000011 */ + 0xc0, 0xc0, /* 1100000011 */ + 0xc0, 0xc0, /* 1100000011 */ + 0xe0, 0xc0, /* 1110000011 */ + 0x61, 0x80, /* 0110000110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x77, 0x00, /* 0111011100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 88 0x58 'X' */ + 0x00, 0x00, /* 0000000000 */ + 0xf7, 0x80, /* 1111011110 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x36, 0x00, /* 0011011000 */ + 0x36, 0x00, /* 0011011000 */ + 0x36, 0x00, /* 0011011000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x36, 0x00, /* 0011011000 */ + 0x36, 0x00, /* 0011011000 */ + 0x36, 0x00, /* 0011011000 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0xf7, 0x80, /* 1111011110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 89 0x59 'Y' */ + 0x00, 0x00, /* 0000000000 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 90 0x5a 'Z' */ + 0x00, 0x00, /* 0000000000 */ + 0x3f, 0x80, /* 0011111110 */ + 0x21, 0x80, /* 0010000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x80, /* 0011000010 */ + 0x3f, 0x80, /* 0011111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 91 0x5b '[' */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x1f, 0x00, /* 0001111100 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x1f, 0x00, /* 0001111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 92 0x5c '\' */ + 0x00, 0x00, /* 0000000000 */ + 0xc0, 0x00, /* 1100000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x00, 0xc0, /* 0000000011 */ + 0x00, 0x00, /* 0000000000 */ + + /* 93 0x5d ']' */ + 0x00, 0x00, /* 0000000000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 94 0x5e '^' */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 95 0x5f '_' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + + /* 96 0x60 '`' */ + 0x04, 0x00, /* 0000010000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 97 0x61 'a' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x31, 0x80, /* 0011000110 */ + 0x21, 0x80, /* 0010000110 */ + 0x07, 0x80, /* 0000011110 */ + 0x39, 0x80, /* 0011100110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x80, /* 0111001110 */ + 0x3d, 0xc0, /* 0011110111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 98 0x62 'b' */ + 0x20, 0x00, /* 0010000000 */ + 0x60, 0x00, /* 0110000000 */ + 0xe0, 0x00, /* 1110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x66, 0x00, /* 0110011000 */ + 0x6f, 0x00, /* 0110111100 */ + 0x73, 0x80, /* 0111001110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x71, 0x80, /* 0111000110 */ + 0x7b, 0x00, /* 0111101100 */ + 0x4e, 0x00, /* 0100111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 99 0x63 'c' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x37, 0x00, /* 0011011100 */ + 0x23, 0x00, /* 0010001100 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x71, 0x00, /* 0111000100 */ + 0x33, 0x00, /* 0011001100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 100 0x64 'd' */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0x80, /* 0000001110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x0d, 0x80, /* 0000110110 */ + 0x37, 0x80, /* 0011011110 */ + 0x23, 0x80, /* 0010001110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x80, /* 0111001110 */ + 0x35, 0x80, /* 0011010110 */ + 0x19, 0xc0, /* 0001100111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 101 0x65 'e' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x19, 0x80, /* 0001100110 */ + 0x0e, 0x00, /* 0000111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 102 0x66 'f' */ + 0x07, 0x00, /* 0000011100 */ + 0x09, 0x80, /* 0000100110 */ + 0x09, 0x80, /* 0000100110 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x7f, 0x00, /* 0111111100 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 103 0x67 'g' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1c, 0x80, /* 0001110010 */ + 0x37, 0x80, /* 0011011110 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x36, 0x00, /* 0011011000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x60, 0x00, /* 0110000000 */ + 0x7f, 0x00, /* 0111111100 */ + 0x3f, 0x80, /* 0011111110 */ + 0x21, 0x80, /* 0010000110 */ + 0x40, 0x80, /* 0100000010 */ + 0x7f, 0x00, /* 0111111100 */ + 0x3e, 0x00, /* 0011111000 */ + + /* 104 0x68 'h' */ + 0x10, 0x00, /* 0001000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x70, 0x00, /* 0111000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x37, 0x00, /* 0011011100 */ + 0x3b, 0x80, /* 0011101110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x7b, 0xc0, /* 0111101111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 105 0x69 'i' */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 106 0x6a 'j' */ + 0x00, 0x00, /* 0000000000 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x07, 0x80, /* 0000011110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x41, 0x80, /* 0100000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x71, 0x80, /* 0111000110 */ + 0x3f, 0x00, /* 0011111100 */ + 0x1c, 0x00, /* 0001110000 */ + + /* 107 0x6b 'k' */ + 0x60, 0x00, /* 0110000000 */ + 0xe0, 0x00, /* 1110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x63, 0x80, /* 0110001110 */ + 0x66, 0x00, /* 0110011000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x78, 0x00, /* 0111100000 */ + 0x70, 0x00, /* 0111000000 */ + 0x78, 0x00, /* 0111100000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x6e, 0x00, /* 0110111000 */ + 0x67, 0x00, /* 0110011100 */ + 0xf3, 0x80, /* 1111001110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 108 0x6c 'l' */ + 0x3c, 0x00, /* 0011110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 109 0x6d 'm' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xdb, 0x80, /* 1101101110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0xed, 0xc0, /* 1110110111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 110 0x6e 'n' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x6f, 0x00, /* 0110111100 */ + 0x7b, 0x80, /* 0111101110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x7b, 0xc0, /* 0111101111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 111 0x6f 'o' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x66, 0x00, /* 0110011000 */ + 0xc3, 0x00, /* 1100001100 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xe1, 0x80, /* 1110000110 */ + 0x73, 0x00, /* 0111001100 */ + 0x3c, 0x00, /* 0011110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 112 0x70 'p' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xde, 0x00, /* 1101111000 */ + 0x76, 0x00, /* 0111011000 */ + 0x63, 0x00, /* 0110001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x71, 0x80, /* 0111000110 */ + 0x7b, 0x00, /* 0111101100 */ + 0x7e, 0x00, /* 0111111000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0xf0, 0x00, /* 1111000000 */ + + /* 113 0x71 'q' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0e, 0xc0, /* 0000111011 */ + 0x1b, 0x80, /* 0001101110 */ + 0x33, 0x80, /* 0011001110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x71, 0x80, /* 0111000110 */ + 0x3b, 0x80, /* 0011101110 */ + 0x1f, 0x80, /* 0001111110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0xc0, /* 0000001111 */ + + /* 114 0x72 'r' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x73, 0x00, /* 0111001100 */ + 0x35, 0x80, /* 0011010110 */ + 0x39, 0x80, /* 0011100110 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x78, 0x00, /* 0111100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 115 0x73 's' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x63, 0x00, /* 0110001100 */ + 0x61, 0x00, /* 0110000100 */ + 0x70, 0x00, /* 0111000000 */ + 0x38, 0x00, /* 0011100000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x07, 0x00, /* 0000011100 */ + 0x43, 0x00, /* 0100001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x7e, 0x00, /* 0111111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 116 0x74 't' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x1c, 0x80, /* 0001110010 */ + 0x0f, 0x00, /* 0000111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 117 0x75 'u' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xf7, 0x80, /* 1111011110 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x77, 0x00, /* 0111011100 */ + 0x3d, 0x80, /* 0011110110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 118 0x76 'v' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xf1, 0xc0, /* 1111000111 */ + 0x60, 0xc0, /* 0110000011 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x19, 0x80, /* 0001100110 */ + 0x1b, 0x00, /* 0001101100 */ + 0x0f, 0x00, /* 0000111100 */ + 0x0f, 0x00, /* 0000111100 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 119 0x77 'w' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xe3, 0xc0, /* 1110001111 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0x6b, 0x00, /* 0110101100 */ + 0x6b, 0x00, /* 0110101100 */ + 0x7e, 0x00, /* 0111111000 */ + 0x36, 0x00, /* 0011011000 */ + 0x36, 0x00, /* 0011011000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 120 0x78 'x' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xf7, 0x80, /* 1111011110 */ + 0x63, 0x00, /* 0110001100 */ + 0x36, 0x00, /* 0011011000 */ + 0x36, 0x00, /* 0011011000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x36, 0x00, /* 0011011000 */ + 0x66, 0x00, /* 0110011000 */ + 0x63, 0x00, /* 0110001100 */ + 0xf7, 0x80, /* 1111011110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 121 0x79 'y' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x61, 0x80, /* 0110000110 */ + 0x33, 0x00, /* 0011001100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x78, 0x00, /* 0111100000 */ + 0x70, 0x00, /* 0111000000 */ + + /* 122 0x7a 'z' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x61, 0x80, /* 0110000110 */ + 0x43, 0x00, /* 0100001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x60, 0x80, /* 0110000010 */ + 0x61, 0x80, /* 0110000110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 123 0x7b '{' */ + 0x07, 0x00, /* 0000011100 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x70, 0x00, /* 0111000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x07, 0x00, /* 0000011100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 124 0x7c '|' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 125 0x7d '}' */ + 0x38, 0x00, /* 0011100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x06, 0x00, /* 0000011000 */ + 0x03, 0x80, /* 0000001110 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x38, 0x00, /* 0011100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 126 0x7e '~' */ + 0x00, 0x00, /* 0000000000 */ + 0x18, 0x80, /* 0001100010 */ + 0x3d, 0x80, /* 0011110110 */ + 0x6f, 0x00, /* 0110111100 */ + 0x46, 0x00, /* 0100011000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 127 0x7f '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x12, 0x00, /* 0001001000 */ + 0x21, 0x00, /* 0010000100 */ + 0x40, 0x80, /* 0100000010 */ + 0x40, 0x80, /* 0100000010 */ + 0x40, 0x80, /* 0100000010 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 128 0x80 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x21, 0x80, /* 0010000110 */ + 0x40, 0x80, /* 0100000010 */ + 0x40, 0x00, /* 0100000000 */ + 0x40, 0x00, /* 0100000000 */ + 0x40, 0x00, /* 0100000000 */ + 0x40, 0x00, /* 0100000000 */ + 0x40, 0x00, /* 0100000000 */ + 0x40, 0x00, /* 0100000000 */ + 0x60, 0x80, /* 0110000010 */ + 0x31, 0x00, /* 0011000100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x08, 0x00, /* 0000100000 */ + 0x04, 0x00, /* 0000010000 */ + 0x02, 0x00, /* 0000001000 */ + 0x02, 0x00, /* 0000001000 */ + 0x1c, 0x00, /* 0001110000 */ + + /* 129 0x81 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7b, 0x80, /* 0111101110 */ + 0x31, 0x00, /* 0011000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x3b, 0x00, /* 0011101100 */ + 0x1c, 0x80, /* 0001110010 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 130 0x82 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x01, 0x00, /* 0000000100 */ + 0x02, 0x00, /* 0000001000 */ + 0x04, 0x00, /* 0000010000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x19, 0x80, /* 0001100110 */ + 0x0e, 0x00, /* 0000111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 131 0x83 '.' */ + 0x04, 0x00, /* 0000010000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1b, 0x00, /* 0001101100 */ + 0x31, 0x80, /* 0011000110 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x31, 0x80, /* 0011000110 */ + 0x21, 0x80, /* 0010000110 */ + 0x07, 0x80, /* 0000011110 */ + 0x39, 0x80, /* 0011100110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x80, /* 0111001110 */ + 0x3d, 0xc0, /* 0011110111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 132 0x84 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x31, 0x80, /* 0011000110 */ + 0x21, 0x80, /* 0010000110 */ + 0x07, 0x80, /* 0000011110 */ + 0x39, 0x80, /* 0011100110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x80, /* 0111001110 */ + 0x3d, 0xc0, /* 0011110111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 133 0x85 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x06, 0x00, /* 0000011000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x31, 0x80, /* 0011000110 */ + 0x21, 0x80, /* 0010000110 */ + 0x07, 0x80, /* 0000011110 */ + 0x39, 0x80, /* 0011100110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x80, /* 0111001110 */ + 0x3d, 0xc0, /* 0011110111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 134 0x86 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1b, 0x00, /* 0001101100 */ + 0x0e, 0x00, /* 0000111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x31, 0x80, /* 0011000110 */ + 0x21, 0x80, /* 0010000110 */ + 0x07, 0x80, /* 0000011110 */ + 0x39, 0x80, /* 0011100110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x80, /* 0111001110 */ + 0x3d, 0xc0, /* 0011110111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 135 0x87 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x31, 0x80, /* 0011000110 */ + 0x20, 0x80, /* 0010000010 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x70, 0x80, /* 0111000010 */ + 0x30, 0x80, /* 0011000010 */ + 0x1f, 0x00, /* 0001111100 */ + 0x04, 0x00, /* 0000010000 */ + 0x02, 0x00, /* 0000001000 */ + 0x01, 0x00, /* 0000000100 */ + 0x0e, 0x00, /* 0000111000 */ + + /* 136 0x88 '.' */ + 0x04, 0x00, /* 0000010000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1b, 0x00, /* 0001101100 */ + 0x31, 0x80, /* 0011000110 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x19, 0x80, /* 0001100110 */ + 0x0e, 0x00, /* 0000111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 137 0x89 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x36, 0x00, /* 0011011000 */ + 0x36, 0x00, /* 0011011000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x19, 0x80, /* 0001100110 */ + 0x0e, 0x00, /* 0000111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 138 0x8a '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x19, 0x80, /* 0001100110 */ + 0x0e, 0x00, /* 0000111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 139 0x8b '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x36, 0x00, /* 0011011000 */ + 0x36, 0x00, /* 0011011000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 140 0x8c '.' */ + 0x08, 0x00, /* 0000100000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x36, 0x00, /* 0011011000 */ + 0x63, 0x00, /* 0110001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 141 0x8d '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 142 0x8e '.' */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x04, 0x00, /* 0000010000 */ + 0x04, 0x00, /* 0000010000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x19, 0x00, /* 0001100100 */ + 0x19, 0x00, /* 0001100100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x31, 0x00, /* 0011000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x60, 0x80, /* 0110000010 */ + 0x60, 0x80, /* 0110000010 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 143 0x8f '.' */ + 0x04, 0x00, /* 0000010000 */ + 0x0a, 0x00, /* 0000101000 */ + 0x0a, 0x00, /* 0000101000 */ + 0x04, 0x00, /* 0000010000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x19, 0x00, /* 0001100100 */ + 0x19, 0x00, /* 0001100100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x31, 0x00, /* 0011000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x60, 0x80, /* 0110000010 */ + 0x60, 0x80, /* 0110000010 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 144 0x90 '.' */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x30, 0x80, /* 0011000010 */ + 0x30, 0x80, /* 0011000010 */ + 0x30, 0x00, /* 0011000000 */ + 0x31, 0x00, /* 0011000100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x31, 0x00, /* 0011000100 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x80, /* 0011000010 */ + 0x30, 0x80, /* 0011000010 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 145 0x91 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3b, 0x80, /* 0011101110 */ + 0x6c, 0xc0, /* 0110110011 */ + 0x4c, 0xc0, /* 0100110011 */ + 0x0c, 0xc0, /* 0000110011 */ + 0x3f, 0xc0, /* 0011111111 */ + 0x6c, 0x00, /* 0110110000 */ + 0xcc, 0x00, /* 1100110000 */ + 0xcc, 0x00, /* 1100110000 */ + 0xee, 0xc0, /* 1110111011 */ + 0x7b, 0x80, /* 0111101110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 146 0x92 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x07, 0xc0, /* 0000011111 */ + 0x0e, 0x40, /* 0000111001 */ + 0x0e, 0x40, /* 0000111001 */ + 0x0e, 0x00, /* 0000111000 */ + 0x16, 0x00, /* 0001011000 */ + 0x16, 0x80, /* 0001011010 */ + 0x17, 0x80, /* 0001011110 */ + 0x16, 0x80, /* 0001011010 */ + 0x3e, 0x00, /* 0011111000 */ + 0x26, 0x00, /* 0010011000 */ + 0x26, 0x00, /* 0010011000 */ + 0x46, 0x40, /* 0100011001 */ + 0x46, 0x40, /* 0100011001 */ + 0xef, 0xc0, /* 1110111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 147 0x93 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x08, 0x00, /* 0000100000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x36, 0x00, /* 0011011000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x66, 0x00, /* 0110011000 */ + 0xc3, 0x00, /* 1100001100 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xe1, 0x80, /* 1110000110 */ + 0x73, 0x00, /* 0111001100 */ + 0x3c, 0x00, /* 0011110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 148 0x94 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x66, 0x00, /* 0110011000 */ + 0xc3, 0x00, /* 1100001100 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xe1, 0x80, /* 1110000110 */ + 0x73, 0x00, /* 0111001100 */ + 0x3c, 0x00, /* 0011110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 149 0x95 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x06, 0x00, /* 0000011000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x66, 0x00, /* 0110011000 */ + 0xc3, 0x00, /* 1100001100 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xe1, 0x80, /* 1110000110 */ + 0x73, 0x00, /* 0111001100 */ + 0x3c, 0x00, /* 0011110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 150 0x96 '.' */ + 0x08, 0x00, /* 0000100000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x36, 0x00, /* 0011011000 */ + 0x63, 0x00, /* 0110001100 */ + 0x00, 0x00, /* 0000000000 */ + 0xf7, 0x80, /* 1111011110 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x77, 0x00, /* 0111011100 */ + 0x3d, 0x80, /* 0011110110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 151 0x97 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x00, 0x00, /* 0000000000 */ + 0xf7, 0x80, /* 1111011110 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x77, 0x00, /* 0111011100 */ + 0x3d, 0x80, /* 0011110110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 152 0x98 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x61, 0x80, /* 0110000110 */ + 0x33, 0x00, /* 0011001100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x78, 0x00, /* 0111100000 */ + 0x70, 0x00, /* 0111000000 */ + + /* 153 0x99 '.' */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x0c, 0x00, /* 0000110000 */ + 0x17, 0x00, /* 0001011100 */ + 0x23, 0x00, /* 0010001100 */ + 0x21, 0x80, /* 0010000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x21, 0x00, /* 0010000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x1a, 0x00, /* 0001101000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 154 0x9a '.' */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x00, 0x00, /* 0000000000 */ + 0xf1, 0xc0, /* 1111000111 */ + 0x60, 0x80, /* 0110000010 */ + 0x60, 0x80, /* 0110000010 */ + 0x60, 0x80, /* 0110000010 */ + 0x60, 0x80, /* 0110000010 */ + 0x60, 0x80, /* 0110000010 */ + 0x60, 0x80, /* 0110000010 */ + 0x60, 0x80, /* 0110000010 */ + 0x60, 0x80, /* 0110000010 */ + 0x71, 0x00, /* 0111000100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 155 0x9b '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x1f, 0x80, /* 0001111110 */ + 0x36, 0x80, /* 0011011010 */ + 0x26, 0x00, /* 0010011000 */ + 0x66, 0x00, /* 0110011000 */ + 0x66, 0x00, /* 0110011000 */ + 0x66, 0x00, /* 0110011000 */ + 0x66, 0x00, /* 0110011000 */ + 0x76, 0x00, /* 0111011000 */ + 0x36, 0x80, /* 0011011010 */ + 0x1f, 0x80, /* 0001111110 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 156 0x9c '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x3b, 0x00, /* 0011101100 */ + 0x33, 0x00, /* 0011001100 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x7e, 0x00, /* 0111111000 */ + 0x7e, 0x00, /* 0111111000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x7c, 0x80, /* 0111110010 */ + 0x7f, 0x80, /* 0111111110 */ + 0x43, 0x00, /* 0100001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 157 0x9d '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x40, 0x80, /* 0100000010 */ + 0x40, 0x80, /* 0100000010 */ + 0x21, 0x00, /* 0010000100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 158 0x9e '.' */ + 0x00, 0x00, /* 0000000000 */ + 0xbf, 0x00, /* 1011111100 */ + 0x40, 0x80, /* 0100000010 */ + 0x40, 0x80, /* 0100000010 */ + 0x7f, 0x00, /* 0111111100 */ + 0x40, 0x00, /* 0100000000 */ + 0x48, 0x00, /* 0100100000 */ + 0x48, 0x00, /* 0100100000 */ + 0x5e, 0x00, /* 0101111000 */ + 0x48, 0x00, /* 0100100000 */ + 0x48, 0x00, /* 0100100000 */ + 0x48, 0x00, /* 0100100000 */ + 0x48, 0x80, /* 0100100010 */ + 0x47, 0x00, /* 0100011100 */ + 0xe0, 0x00, /* 1110000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 159 0x9f '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x03, 0x00, /* 0000001100 */ + 0x04, 0x80, /* 0000010010 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x09, 0x00, /* 0000100100 */ + 0x3e, 0x00, /* 0011111000 */ + 0x48, 0x00, /* 0100100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x08, 0x00, /* 0000100000 */ + 0x90, 0x00, /* 1001000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 160 0xa0 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x31, 0x80, /* 0011000110 */ + 0x21, 0x80, /* 0010000110 */ + 0x07, 0x80, /* 0000011110 */ + 0x39, 0x80, /* 0011100110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x80, /* 0111001110 */ + 0x3d, 0xc0, /* 0011110111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 161 0xa1 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x03, 0x00, /* 0000001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 162 0xa2 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x66, 0x00, /* 0110011000 */ + 0xc3, 0x00, /* 1100001100 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xc1, 0x80, /* 1100000110 */ + 0xe1, 0x80, /* 1110000110 */ + 0x73, 0x00, /* 0111001100 */ + 0x3c, 0x00, /* 0011110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 163 0xa3 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x00, 0x00, /* 0000000000 */ + 0xf7, 0x80, /* 1111011110 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x77, 0x00, /* 0111011100 */ + 0x3d, 0x80, /* 0011110110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 164 0xa4 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x38, 0x80, /* 0011100010 */ + 0x7f, 0x80, /* 0111111110 */ + 0x47, 0x00, /* 0100011100 */ + 0x00, 0x00, /* 0000000000 */ + 0x6f, 0x00, /* 0110111100 */ + 0x7b, 0x80, /* 0111101110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x7b, 0xc0, /* 0111101111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 165 0xa5 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x38, 0x80, /* 0011100010 */ + 0x7f, 0x80, /* 0111111110 */ + 0x47, 0x00, /* 0100011100 */ + 0x00, 0x00, /* 0000000000 */ + 0xe3, 0xc0, /* 1110001111 */ + 0x71, 0x80, /* 0111000110 */ + 0x79, 0x80, /* 0111100110 */ + 0x79, 0x80, /* 0111100110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x67, 0x80, /* 0110011110 */ + 0x63, 0x80, /* 0110001110 */ + 0x61, 0x80, /* 0110000110 */ + 0xf0, 0xc0, /* 1111000011 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 166 0xa6 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x63, 0x00, /* 0110001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x0f, 0x00, /* 0000111100 */ + 0x33, 0x00, /* 0011001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x67, 0x00, /* 0110011100 */ + 0x3b, 0x80, /* 0011101110 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 167 0xa7 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x33, 0x00, /* 0011001100 */ + 0x21, 0x80, /* 0010000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x00, /* 0110000100 */ + 0x33, 0x00, /* 0011001100 */ + 0x1c, 0x00, /* 0001110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 168 0xa8 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x00, 0x00, /* 0000000000 */ + 0x06, 0x00, /* 0000011000 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x80, /* 0110000010 */ + 0x73, 0x80, /* 0111001110 */ + 0x3f, 0x00, /* 0011111100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 169 0xa9 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 170 0xaa '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 171 0xab '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x20, 0x00, /* 0010000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x20, 0x00, /* 0010000000 */ + 0x20, 0x80, /* 0010000010 */ + 0x21, 0x00, /* 0010000100 */ + 0x22, 0x00, /* 0010001000 */ + 0x74, 0x00, /* 0111010000 */ + 0x08, 0x00, /* 0000100000 */ + 0x17, 0x00, /* 0001011100 */ + 0x28, 0x80, /* 0010100010 */ + 0x43, 0x00, /* 0100001100 */ + 0x04, 0x00, /* 0000010000 */ + 0x08, 0x00, /* 0000100000 */ + 0x0f, 0x80, /* 0000111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 172 0xac '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x20, 0x00, /* 0010000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x20, 0x00, /* 0010000000 */ + 0x20, 0x80, /* 0010000010 */ + 0x21, 0x00, /* 0010000100 */ + 0x22, 0x00, /* 0010001000 */ + 0x74, 0x00, /* 0111010000 */ + 0x09, 0x00, /* 0000100100 */ + 0x13, 0x00, /* 0001001100 */ + 0x25, 0x00, /* 0010010100 */ + 0x49, 0x00, /* 0100100100 */ + 0x1f, 0x80, /* 0001111110 */ + 0x01, 0x00, /* 0000000100 */ + 0x01, 0x00, /* 0000000100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 173 0xad '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 174 0xae '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0d, 0x80, /* 0000110110 */ + 0x1b, 0x00, /* 0001101100 */ + 0x36, 0x00, /* 0011011000 */ + 0x6c, 0x00, /* 0110110000 */ + 0xd8, 0x00, /* 1101100000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x36, 0x00, /* 0011011000 */ + 0x1b, 0x00, /* 0001101100 */ + 0x0d, 0x80, /* 0000110110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 175 0xaf '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x36, 0x00, /* 0011011000 */ + 0x1b, 0x00, /* 0001101100 */ + 0x0d, 0x80, /* 0000110110 */ + 0x06, 0xc0, /* 0000011011 */ + 0x0d, 0x80, /* 0000110110 */ + 0x1b, 0x00, /* 0001101100 */ + 0x36, 0x00, /* 0011011000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 176 0xb0 '.' */ + 0xc3, 0x00, /* 1100001100 */ + 0x41, 0x00, /* 0100000100 */ + 0x18, 0x40, /* 0001100001 */ + 0x10, 0x40, /* 0001000001 */ + 0xc3, 0x00, /* 1100001100 */ + 0x41, 0x00, /* 0100000100 */ + 0x18, 0x40, /* 0001100001 */ + 0x10, 0x40, /* 0001000001 */ + 0xc3, 0x00, /* 1100001100 */ + 0x41, 0x00, /* 0100000100 */ + 0x18, 0x40, /* 0001100001 */ + 0x10, 0x40, /* 0001000001 */ + 0xc3, 0x00, /* 1100001100 */ + 0x41, 0x00, /* 0100000100 */ + 0x18, 0x40, /* 0001100001 */ + 0x10, 0x40, /* 0001000001 */ + 0xc3, 0x00, /* 1100001100 */ + 0x41, 0x00, /* 0100000100 */ + + /* 177 0xb1 '.' */ + 0x11, 0x00, /* 0001000100 */ + 0xbb, 0x80, /* 1011101110 */ + 0x11, 0x00, /* 0001000100 */ + 0x44, 0x40, /* 0100010001 */ + 0xee, 0xc0, /* 1110111011 */ + 0x44, 0x40, /* 0100010001 */ + 0x11, 0x00, /* 0001000100 */ + 0xbb, 0x80, /* 1011101110 */ + 0x11, 0x00, /* 0001000100 */ + 0x44, 0x40, /* 0100010001 */ + 0xee, 0xc0, /* 1110111011 */ + 0x44, 0x40, /* 0100010001 */ + 0x11, 0x00, /* 0001000100 */ + 0xbb, 0x80, /* 1011101110 */ + 0x11, 0x00, /* 0001000100 */ + 0x44, 0x40, /* 0100010001 */ + 0xee, 0xc0, /* 1110111011 */ + 0x44, 0x40, /* 0100010001 */ + + /* 178 0xb2 '.' */ + 0x3c, 0xc0, /* 0011110011 */ + 0xbe, 0xc0, /* 1011111011 */ + 0xe7, 0x80, /* 1110011110 */ + 0xef, 0x80, /* 1110111110 */ + 0x3c, 0xc0, /* 0011110011 */ + 0xbe, 0xc0, /* 1011111011 */ + 0xe7, 0x80, /* 1110011110 */ + 0xef, 0x80, /* 1110111110 */ + 0x3c, 0xc0, /* 0011110011 */ + 0xbe, 0xc0, /* 1011111011 */ + 0xe7, 0x80, /* 1110011110 */ + 0xef, 0x80, /* 1110111110 */ + 0x3c, 0xc0, /* 0011110011 */ + 0xbe, 0xc0, /* 1011111011 */ + 0xe7, 0x80, /* 1110011110 */ + 0xef, 0x80, /* 1110111110 */ + 0x3c, 0xc0, /* 0011110011 */ + 0xbe, 0xc0, /* 1011111011 */ + + /* 179 0xb3 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 180 0xb4 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 181 0xb5 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 182 0xb6 '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0xfb, 0x00, /* 1111101100 */ + 0xfb, 0x00, /* 1111101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 183 0xb7 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0x00, /* 1111111100 */ + 0xff, 0x00, /* 1111111100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 184 0xb8 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xfc, 0x00, /* 1111110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 185 0xb9 '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0xfb, 0x00, /* 1111101100 */ + 0xfb, 0x00, /* 1111101100 */ + 0x03, 0x00, /* 0000001100 */ + 0xfb, 0x00, /* 1111101100 */ + 0xfb, 0x00, /* 1111101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 186 0xba '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 187 0xbb '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0x00, /* 1111111100 */ + 0xff, 0x00, /* 1111111100 */ + 0x03, 0x00, /* 0000001100 */ + 0xfb, 0x00, /* 1111101100 */ + 0xfb, 0x00, /* 1111101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 188 0xbc '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0xfb, 0x00, /* 1111101100 */ + 0xfb, 0x00, /* 1111101100 */ + 0x03, 0x00, /* 0000001100 */ + 0xff, 0x00, /* 1111111100 */ + 0xff, 0x00, /* 1111111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 189 0xbd '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0xff, 0x00, /* 1111111100 */ + 0xff, 0x00, /* 1111111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 190 0xbe '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 191 0xbf '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xfc, 0x00, /* 1111110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 192 0xc0 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 193 0xc1 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 194 0xc2 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 195 0xc3 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 196 0xc4 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 197 0xc5 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 198 0xc6 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 199 0xc7 '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0xc0, /* 0001101111 */ + 0x1b, 0xc0, /* 0001101111 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 200 0xc8 '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0xc0, /* 0001101111 */ + 0x1b, 0xc0, /* 0001101111 */ + 0x18, 0x00, /* 0001100000 */ + 0x1f, 0xc0, /* 0001111111 */ + 0x1f, 0xc0, /* 0001111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 201 0xc9 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0xc0, /* 0001111111 */ + 0x1f, 0xc0, /* 0001111111 */ + 0x18, 0x00, /* 0001100000 */ + 0x1b, 0xc0, /* 0001101111 */ + 0x1b, 0xc0, /* 0001101111 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 202 0xca '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0xfb, 0xc0, /* 1111101111 */ + 0xfb, 0xc0, /* 1111101111 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 203 0xcb '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0xfb, 0xc0, /* 1111101111 */ + 0xfb, 0xc0, /* 1111101111 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 204 0xcc '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0xc0, /* 0001101111 */ + 0x1b, 0xc0, /* 0001101111 */ + 0x18, 0x00, /* 0001100000 */ + 0x1b, 0xc0, /* 0001101111 */ + 0x1b, 0xc0, /* 0001101111 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 205 0xcd '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 206 0xce '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0xfb, 0xc0, /* 1111101111 */ + 0xfb, 0xc0, /* 1111101111 */ + 0x00, 0x00, /* 0000000000 */ + 0xfb, 0xc0, /* 1111101111 */ + 0xfb, 0xc0, /* 1111101111 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 207 0xcf '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 208 0xd0 '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 209 0xd1 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 210 0xd2 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 211 0xd3 '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1f, 0xc0, /* 0001111111 */ + 0x1f, 0xc0, /* 0001111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 212 0xd4 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 213 0xd5 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 214 0xd6 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0xc0, /* 0001111111 */ + 0x1f, 0xc0, /* 0001111111 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 215 0xd7 '.' */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + 0x1b, 0x00, /* 0001101100 */ + + /* 216 0xd8 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 217 0xd9 '.' */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0xfc, 0x00, /* 1111110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 218 0xda '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + + /* 219 0xdb '.' */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + + /* 220 0xdc '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + + /* 221 0xdd '.' */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + 0xf8, 0x00, /* 1111100000 */ + + /* 222 0xde '.' */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + 0x07, 0xc0, /* 0000011111 */ + + /* 223 0xdf '.' */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0xff, 0xc0, /* 1111111111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 224 0xe0 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1c, 0x80, /* 0001110010 */ + 0x35, 0x80, /* 0011010110 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x63, 0x00, /* 0110001100 */ + 0x37, 0x80, /* 0011011110 */ + 0x1c, 0x80, /* 0001110010 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 225 0xe1 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x63, 0x00, /* 0110001100 */ + 0x6f, 0x00, /* 0110111100 */ + 0x63, 0x00, /* 0110001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x63, 0x00, /* 0110001100 */ + 0x6e, 0x00, /* 0110111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 226 0xe2 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 227 0xe3 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 228 0xe4 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0x80, /* 1111111110 */ + 0x60, 0x00, /* 0110000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x80, /* 0011000010 */ + 0x61, 0x80, /* 0110000110 */ + 0xff, 0x80, /* 1111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 229 0xe5 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1f, 0xc0, /* 0001111111 */ + 0x36, 0x00, /* 0011011000 */ + 0x63, 0x00, /* 0110001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x33, 0x00, /* 0011001100 */ + 0x3e, 0x00, /* 0011111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 230 0xe6 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x73, 0x80, /* 0111001110 */ + 0x6d, 0x80, /* 0110110110 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0xc0, 0x00, /* 1100000000 */ + + /* 231 0xe7 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x01, 0x80, /* 0000000110 */ + 0x36, 0x40, /* 0011011001 */ + 0x5e, 0x00, /* 0101111000 */ + 0x8c, 0x00, /* 1000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 232 0xe8 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x33, 0x00, /* 0011001100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 233 0xe9 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x1f, 0x00, /* 0001111100 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x60, 0xc0, /* 0110000011 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x7f, 0xc0, /* 0111111111 */ + 0x60, 0xc0, /* 0110000011 */ + 0x31, 0x80, /* 0011000110 */ + 0x31, 0x80, /* 0011000110 */ + 0x1f, 0x00, /* 0001111100 */ + 0x0e, 0x00, /* 0000111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 234 0xea '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0xc0, 0xc0, /* 1100000011 */ + 0xc0, 0xc0, /* 1100000011 */ + 0xc0, 0xc0, /* 1100000011 */ + 0x61, 0x80, /* 0110000110 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0xf3, 0xc0, /* 1111001111 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 235 0xeb '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x07, 0x00, /* 0000011100 */ + 0x1f, 0x80, /* 0001111110 */ + 0x30, 0xc0, /* 0011000011 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x3e, 0x00, /* 0011111000 */ + 0x66, 0x00, /* 0110011000 */ + 0xc3, 0x00, /* 1100001100 */ + 0xc3, 0x00, /* 1100001100 */ + 0xc3, 0x00, /* 1100001100 */ + 0x66, 0x00, /* 0110011000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 236 0xec '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x33, 0x00, /* 0011001100 */ + 0x6d, 0x80, /* 0110110110 */ + 0xcc, 0xc0, /* 1100110011 */ + 0xcc, 0xc0, /* 1100110011 */ + 0xcc, 0xc0, /* 1100110011 */ + 0xcc, 0xc0, /* 1100110011 */ + 0x6d, 0x80, /* 0110110110 */ + 0x33, 0x00, /* 0011001100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 237 0xed '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x01, 0x80, /* 0000000110 */ + 0x01, 0x80, /* 0000000110 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x37, 0x00, /* 0011011100 */ + 0x6d, 0x80, /* 0110110110 */ + 0xcc, 0xc0, /* 1100110011 */ + 0xcc, 0xc0, /* 1100110011 */ + 0xcc, 0xc0, /* 1100110011 */ + 0xcc, 0xc0, /* 1100110011 */ + 0x6d, 0x80, /* 0110110110 */ + 0x3b, 0x00, /* 0011101100 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x60, 0x00, /* 0110000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 238 0xee '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x03, 0x80, /* 0000001110 */ + 0x0e, 0x00, /* 0000111000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x3f, 0x80, /* 0011111110 */ + 0x3f, 0x80, /* 0011111110 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x18, 0x00, /* 0001100000 */ + 0x18, 0x00, /* 0001100000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x03, 0x80, /* 0000001110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 239 0xef '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x33, 0x00, /* 0011001100 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x61, 0x80, /* 0110000110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 240 0xf0 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 241 0xf1 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 242 0xf2 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xe0, 0x00, /* 1110000000 */ + 0x38, 0x00, /* 0011100000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x03, 0x80, /* 0000001110 */ + 0x0e, 0x00, /* 0000111000 */ + 0x38, 0x00, /* 0011100000 */ + 0xe0, 0x00, /* 1110000000 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0x00, /* 1111111100 */ + 0xff, 0x00, /* 1111111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 243 0xf3 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x03, 0x80, /* 0000001110 */ + 0x0e, 0x00, /* 0000111000 */ + 0x38, 0x00, /* 0011100000 */ + 0xe0, 0x00, /* 1110000000 */ + 0x38, 0x00, /* 0011100000 */ + 0x0e, 0x00, /* 0000111000 */ + 0x03, 0x80, /* 0000001110 */ + 0x00, 0x00, /* 0000000000 */ + 0xff, 0x80, /* 1111111110 */ + 0xff, 0x80, /* 1111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 244 0xf4 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x30, 0x00, /* 0011000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 245 0xf5 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x03, 0x00, /* 0000001100 */ + 0x00, 0x00, /* 0000000000 */ + + /* 246 0xf6 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 247 0xf7 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x38, 0x00, /* 0011100000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x06, 0xc0, /* 0000011011 */ + 0x03, 0x80, /* 0000001110 */ + 0x38, 0x00, /* 0011100000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x06, 0xc0, /* 0000011011 */ + 0x03, 0x80, /* 0000001110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 248 0xf8 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x33, 0x00, /* 0011001100 */ + 0x33, 0x00, /* 0011001100 */ + 0x1e, 0x00, /* 0001111000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 249 0xf9 '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 250 0xfa '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 251 0xfb '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0f, 0xc0, /* 0000111111 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0xcc, 0x00, /* 1100110000 */ + 0x6c, 0x00, /* 0110110000 */ + 0x3c, 0x00, /* 0011110000 */ + 0x1c, 0x00, /* 0001110000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 252 0xfc '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x27, 0x00, /* 0010011100 */ + 0x7b, 0x00, /* 0111101100 */ + 0x31, 0x00, /* 0011000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x31, 0x00, /* 0011000100 */ + 0x7b, 0x80, /* 0111101110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 253 0xfd '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x1e, 0x00, /* 0001111000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x63, 0x00, /* 0110001100 */ + 0x43, 0x00, /* 0100001100 */ + 0x06, 0x00, /* 0000011000 */ + 0x0c, 0x00, /* 0000110000 */ + 0x18, 0x00, /* 0001100000 */ + 0x30, 0x80, /* 0011000010 */ + 0x7f, 0x80, /* 0111111110 */ + 0x7f, 0x80, /* 0111111110 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 254 0xfe '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x3f, 0x00, /* 0011111100 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + + /* 255 0xff '.' */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + 0x00, 0x00, /* 0000000000 */ + +}; + + +struct font_desc font_10x18 = { + FONT10x18_IDX, + "10x18", + 10, + 18, + fontdata_10x18, +#ifdef __sparc__ + 5 +#else + -1 +#endif +}; diff --git a/drivers/video/console/font_7x14.c b/drivers/video/console/font_7x14.c new file mode 100644 index 0000000..1fa7fcf --- /dev/null +++ b/drivers/video/console/font_7x14.c @@ -0,0 +1,4118 @@ +/**************************************/ +/* this file adapted from font_8x16.c */ +/* by Jurriaan Kalkman 05-2005 */ +/**************************************/ + +#include + +#define FONTDATAMAX 3584 + +static unsigned char fontdata_7x14[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 1 0x01 '^A' */ + 0x00, /* 0000000 */ + 0x7c, /* 0111110 */ + 0x82, /* 1000001 */ + 0xaa, /* 1010101 */ + 0x82, /* 1000001 */ + 0x82, /* 1000001 */ + 0xba, /* 1011101 */ + 0x92, /* 1001001 */ + 0x82, /* 1000001 */ + 0x7c, /* 0111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 2 0x02 '^B' */ + 0x00, /* 0000000 */ + 0x7c, /* 0111110 */ + 0xfe, /* 1111111 */ + 0xd6, /* 1101011 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xc6, /* 1100011 */ + 0xee, /* 1110111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0x7c, /* 0111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 3 0x03 '^C' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x6c, /* 0110110 */ + 0x7c, /* 0111110 */ + 0xfe, /* 1111111 */ + 0x7c, /* 0111110 */ + 0x38, /* 0011100 */ + 0x18, /* 0001100 */ + 0x10, /* 0001000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 4 0x04 '^D' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x10, /* 0001000 */ + 0x38, /* 0011100 */ + 0x7c, /* 0111110 */ + 0xfe, /* 1111111 */ + 0x7c, /* 0111110 */ + 0x38, /* 0011100 */ + 0x10, /* 0001000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 5 0x05 '^E' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x38, /* 0011100 */ + 0x38, /* 0011100 */ + 0x38, /* 0011100 */ + 0xee, /* 1110111 */ + 0xee, /* 1110111 */ + 0xee, /* 1110111 */ + 0x10, /* 0001000 */ + 0x10, /* 0001000 */ + 0x38, /* 0011100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 6 0x06 '^F' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x10, /* 0001000 */ + 0x38, /* 0011100 */ + 0x7c, /* 0111110 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0x7c, /* 0111110 */ + 0x10, /* 0001000 */ + 0x10, /* 0001000 */ + 0x38, /* 0011100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x3c, /* 0011110 */ + 0x3c, /* 0011110 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 8 0x08 '^H' */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xe6, /* 1110011 */ + 0xc2, /* 1100001 */ + 0xc2, /* 1100001 */ + 0xe6, /* 1110011 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0x44, /* 0100010 */ + 0x6c, /* 0110110 */ + 0x38, /* 0011100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 10 0x0a '^J' */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xc6, /* 1100011 */ + 0x92, /* 1001001 */ + 0xba, /* 1011101 */ + 0x92, /* 1001001 */ + 0xc6, /* 1100011 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + + /* 11 0x0b '^K' */ + 0x00, /* 0000000 */ + 0x1e, /* 0001111 */ + 0x0e, /* 0000111 */ + 0x1a, /* 0001101 */ + 0x1a, /* 0001101 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 12 0x0c '^L' */ + 0x00, /* 0000000 */ + 0x3c, /* 0011110 */ + 0x66, /* 0110011 */ + 0x66, /* 0110011 */ + 0x66, /* 0110011 */ + 0x66, /* 0110011 */ + 0x3c, /* 0011110 */ + 0x18, /* 0001100 */ + 0x7e, /* 0111111 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 13 0x0d '^M' */ + 0x00, /* 0000000 */ + 0x3e, /* 0011111 */ + 0x36, /* 0011011 */ + 0x3e, /* 0011111 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x70, /* 0111000 */ + 0xf0, /* 1111000 */ + 0xe0, /* 1110000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 14 0x0e '^N' */ + 0x00, /* 0000000 */ + 0x7e, /* 0111111 */ + 0x66, /* 0110011 */ + 0x7e, /* 0111111 */ + 0x66, /* 0110011 */ + 0x66, /* 0110011 */ + 0x66, /* 0110011 */ + 0x66, /* 0110011 */ + 0x6e, /* 0110111 */ + 0xee, /* 1110111 */ + 0xec, /* 1110110 */ + 0xc0, /* 1100000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 15 0x0f '^O' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x10, /* 0001000 */ + 0x10, /* 0001000 */ + 0xd6, /* 1101011 */ + 0x38, /* 0011100 */ + 0xee, /* 1110111 */ + 0x38, /* 0011100 */ + 0xd6, /* 1101011 */ + 0x10, /* 0001000 */ + 0x10, /* 0001000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 16 0x10 '^P' */ + 0x00, /* 0000000 */ + 0x80, /* 1000000 */ + 0xc0, /* 1100000 */ + 0xe0, /* 1110000 */ + 0xf0, /* 1111000 */ + 0xfc, /* 1111110 */ + 0xf0, /* 1111000 */ + 0xe0, /* 1110000 */ + 0xc0, /* 1100000 */ + 0x80, /* 1000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 17 0x11 '^Q' */ + 0x00, /* 0000000 */ + 0x04, /* 0000010 */ + 0x0c, /* 0000110 */ + 0x1c, /* 0001110 */ + 0x3c, /* 0011110 */ + 0xfc, /* 1111110 */ + 0x3c, /* 0011110 */ + 0x1c, /* 0001110 */ + 0x0c, /* 0000110 */ + 0x04, /* 0000010 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 18 0x12 '^R' */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x3c, /* 0011110 */ + 0x7e, /* 0111111 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x7e, /* 0111111 */ + 0x3c, /* 0011110 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 19 0x13 '^S' */ + 0x00, /* 0000000 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 20 0x14 '^T' */ + 0x00, /* 0000000 */ + 0x7e, /* 0111111 */ + 0xd4, /* 1101010 */ + 0xd4, /* 1101010 */ + 0xd4, /* 1101010 */ + 0x74, /* 0111010 */ + 0x14, /* 0001010 */ + 0x14, /* 0001010 */ + 0x14, /* 0001010 */ + 0x14, /* 0001010 */ + 0x16, /* 0001011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 21 0x15 '^U' */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0x60, /* 0110000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0x6c, /* 0110110 */ + 0x38, /* 0011100 */ + 0x18, /* 0001100 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 22 0x16 '^V' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0xfc, /* 1111110 */ + 0xfc, /* 1111110 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 23 0x17 '^W' */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x3c, /* 0011110 */ + 0x7e, /* 0111111 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x7e, /* 0111111 */ + 0x3c, /* 0011110 */ + 0x18, /* 0001100 */ + 0x7e, /* 0111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 24 0x18 '^X' */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x3c, /* 0011110 */ + 0x7e, /* 0111111 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 25 0x19 '^Y' */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x7e, /* 0111111 */ + 0x3c, /* 0011110 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0xfc, /* 1111110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xfc, /* 1111110 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x28, /* 0010100 */ + 0x6c, /* 0110110 */ + 0xfe, /* 1111111 */ + 0x6c, /* 0110110 */ + 0x28, /* 0010100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0x78, /* 0111100 */ + 0xfc, /* 1111110 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0xfc, /* 1111110 */ + 0x78, /* 0111100 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x3c, /* 0011110 */ + 0x3c, /* 0011110 */ + 0x3c, /* 0011110 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 34 0x22 '"' */ + 0x00, /* 0000000 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x28, /* 0010100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 0000000 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 36 0x24 '$' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xc4, /* 1100010 */ + 0xc0, /* 1100000 */ + 0x78, /* 0111100 */ + 0x0c, /* 0000110 */ + 0x8c, /* 1000110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xc0, /* 1100000 */ + 0xc4, /* 1100010 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xcc, /* 1100110 */ + 0x8c, /* 1000110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 0000000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x38, /* 0011100 */ + 0x78, /* 0111100 */ + 0xde, /* 1101111 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xdc, /* 1101110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 39 0x27 ''' */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 40 0x28 '(' */ + 0x00, /* 0000000 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x0c, /* 0000110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 41 0x29 ')' */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x6c, /* 0110110 */ + 0x38, /* 0011100 */ + 0xfe, /* 1111111 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x10, /* 0001000 */ + 0x10, /* 0001000 */ + 0x7c, /* 0111110 */ + 0x10, /* 0001000 */ + 0x10, /* 0001000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 45 0x2d '-' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 47 0x2f '/' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x04, /* 0000010 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xc0, /* 1100000 */ + 0x80, /* 1000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xdc, /* 1101110 */ + 0xec, /* 1110110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x38, /* 0011100 */ + 0x78, /* 0111100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x7c, /* 0111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x38, /* 0011100 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 0000000 */ + 0x0c, /* 0000110 */ + 0x1c, /* 0001110 */ + 0x3c, /* 0011110 */ + 0x6c, /* 0110110 */ + 0xcc, /* 1100110 */ + 0xfe, /* 1111111 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xf8, /* 1111100 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xf8, /* 1111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x7c, /* 0111110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x70, /* 0111000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 60 0x3c '<' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x04, /* 0000010 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x0c, /* 0000110 */ + 0x04, /* 0000010 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x7c, /* 0111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x7c, /* 0111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 62 0x3e '>' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x40, /* 0100000 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0x40, /* 0100000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 63 0x3f '?' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xdc, /* 1101110 */ + 0xdc, /* 1101110 */ + 0xd8, /* 1101100 */ + 0xc0, /* 1100000 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 0000000 */ + 0xf8, /* 1111100 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x78, /* 0111100 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xf8, /* 1111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 0000000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0xc4, /* 1100010 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc4, /* 1100010 */ + 0x6c, /* 0110110 */ + 0x38, /* 0011100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 0000000 */ + 0xf0, /* 1111000 */ + 0xd8, /* 1101100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xd8, /* 1101100 */ + 0xf0, /* 1111000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 0000000 */ + 0x7c, /* 0111110 */ + 0x6c, /* 0110110 */ + 0x64, /* 0110010 */ + 0x68, /* 0110100 */ + 0x78, /* 0111100 */ + 0x68, /* 0110100 */ + 0x60, /* 0110000 */ + 0x64, /* 0110010 */ + 0x6c, /* 0110110 */ + 0x7c, /* 0111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 0000000 */ + 0x7c, /* 0111110 */ + 0x64, /* 0110010 */ + 0x60, /* 0110000 */ + 0x68, /* 0110100 */ + 0x78, /* 0111100 */ + 0x68, /* 0110100 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x70, /* 0111000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 0000000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0xc4, /* 1100010 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xdc, /* 1101110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x6c, /* 0110110 */ + 0x34, /* 0011010 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 0000000 */ + 0x3c, /* 0011110 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x3c, /* 0011110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 74 0x4a 'J' */ + 0x00, /* 0000000 */ + 0x1c, /* 0001110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 75 0x4b 'K' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xd8, /* 1101100 */ + 0xf0, /* 1111000 */ + 0xf0, /* 1111000 */ + 0xd8, /* 1101100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 76 0x4c 'L' */ + 0x00, /* 0000000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc4, /* 1100010 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 77 0x4d 'M' */ + 0x00, /* 0000000 */ + 0xc6, /* 1100011 */ + 0xee, /* 1110111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xd6, /* 1101011 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 78 0x4e 'N' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xec, /* 1110110 */ + 0xec, /* 1110110 */ + 0xfc, /* 1111110 */ + 0xdc, /* 1101110 */ + 0xdc, /* 1101110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 79 0x4f 'O' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 0000000 */ + 0xf8, /* 1111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xf8, /* 1111100 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xdc, /* 1101110 */ + 0x78, /* 0111100 */ + 0x18, /* 0001100 */ + 0x1c, /* 0001110 */ + 0x00, /* 0000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 0000000 */ + 0xf8, /* 1111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xf8, /* 1111100 */ + 0xd8, /* 1101100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 0000000 */ + 0x7c, /* 0111110 */ + 0xc4, /* 1100010 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0x60, /* 0110000 */ + 0x38, /* 0011100 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x8c, /* 1000110 */ + 0xf8, /* 1111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0xfc, /* 1111110 */ + 0xb4, /* 1011010 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xfc, /* 1111110 */ + 0x48, /* 0100100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 90 0x5a 'Z' */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0x8c, /* 1000110 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xc4, /* 1100010 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 91 0x5b '[' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 92 0x5c '\' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x80, /* 1000000 */ + 0xc0, /* 1100000 */ + 0xe0, /* 1110000 */ + 0x70, /* 0111000 */ + 0x38, /* 0011100 */ + 0x1c, /* 0001110 */ + 0x0c, /* 0000110 */ + 0x04, /* 0000010 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 93 0x5d ']' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 0001000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0xc6, /* 1100011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + + /* 96 0x60 '`' */ + 0x00, /* 0000000 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0x0c, /* 0000110 */ + 0x7c, /* 0111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 0000000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xf0, /* 1111000 */ + 0xd8, /* 1101100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xf8, /* 1111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 0000000 */ + 0x1c, /* 0001110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x3c, /* 0011110 */ + 0x6c, /* 0110110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 0000000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0x64, /* 0110010 */ + 0x60, /* 0110000 */ + 0xf0, /* 1111000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0xf0, /* 1111000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x76, /* 0111011 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x7c, /* 0111110 */ + 0x0c, /* 0000110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + + /* 104 0x68 'h' */ + 0x00, /* 0000000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xd8, /* 1101100 */ + 0xec, /* 1110110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x70, /* 0111000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 106 0x6a 'j' */ + 0x00, /* 0000000 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x00, /* 0000000 */ + 0x1c, /* 0001110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + + /* 107 0x6b 'k' */ + 0x00, /* 0000000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0xd8, /* 1101100 */ + 0xf0, /* 1111000 */ + 0xf0, /* 1111000 */ + 0xd8, /* 1101100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 108 0x6c 'l' */ + 0x00, /* 0000000 */ + 0x70, /* 0111000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xec, /* 1110110 */ + 0xfe, /* 1111111 */ + 0xd6, /* 1101011 */ + 0xd6, /* 1101011 */ + 0xd6, /* 1101011 */ + 0xd6, /* 1101011 */ + 0xd6, /* 1101011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xb8, /* 1011100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xb8, /* 1011100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xf8, /* 1111100 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + + /* 113 0x71 'q' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x74, /* 0111010 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x7c, /* 0111110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + + /* 114 0x72 'r' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xb8, /* 1011100 */ + 0xec, /* 1110110 */ + 0xcc, /* 1100110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 115 0x73 's' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 116 0x74 't' */ + 0x00, /* 0000000 */ + 0x10, /* 0001000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xfc, /* 1111110 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x36, /* 0011011 */ + 0x1c, /* 0001110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0xd6, /* 1101011 */ + 0xd6, /* 1101011 */ + 0xd6, /* 1101011 */ + 0xfe, /* 1111111 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x7c, /* 0111110 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0xf0, /* 1111000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 123 0x7b '{' */ + 0x00, /* 0000000 */ + 0x1c, /* 0001110 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xe0, /* 1110000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x1c, /* 0001110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 124 0x7c '|' */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 125 0x7d '}' */ + 0x00, /* 0000000 */ + 0x70, /* 0111000 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x0e, /* 0000111 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x70, /* 0111000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 126 0x7e '~' */ + 0x00, /* 0000000 */ + 0xec, /* 1110110 */ + 0xb8, /* 1011100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 127 0x7f '' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x10, /* 0001000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 128 0x80 '€' */ + 0x00, /* 0000000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0xc4, /* 1100010 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc4, /* 1100010 */ + 0x6c, /* 0110110 */ + 0x38, /* 0011100 */ + 0x18, /* 0001100 */ + 0x70, /* 0111000 */ + 0x00, /* 0000000 */ + + /* 129 0x81 '' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 130 0x82 '‚' */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 131 0x83 'ƒ' */ + 0x10, /* 0001000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0x0c, /* 0000110 */ + 0x7c, /* 0111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 132 0x84 '„' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0x0c, /* 0000110 */ + 0x7c, /* 0111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 133 0x85 '…' */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0x0c, /* 0000110 */ + 0x7c, /* 0111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 134 0x86 '†' */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0x38, /* 0011100 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0x0c, /* 0000110 */ + 0x7c, /* 0111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xe0, /* 1110000 */ + + /* 136 0x88 'ˆ' */ + 0x10, /* 0001000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 137 0x89 '‰' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 138 0x8a 'Š' */ + 0xc0, /* 1100000 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 139 0x8b '‹' */ + 0x00, /* 0000000 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x38, /* 0011100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x3c, /* 0011110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 140 0x8c 'Œ' */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x70, /* 0111000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 141 0x8d '' */ + 0xc0, /* 1100000 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x70, /* 0111000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 142 0x8e 'Ž' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 143 0x8f '' */ + 0x30, /* 0011000 */ + 0x48, /* 0100100 */ + 0x48, /* 0100100 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 144 0x90 '' */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0xc4, /* 1100010 */ + 0xd0, /* 1101000 */ + 0xf0, /* 1111000 */ + 0xd0, /* 1101000 */ + 0xc4, /* 1100010 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xec, /* 1110110 */ + 0x36, /* 0011011 */ + 0x36, /* 0011011 */ + 0x7e, /* 0111111 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0x6e, /* 0110111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 146 0x92 '’' */ + 0x00, /* 0000000 */ + 0x3e, /* 0011111 */ + 0x6c, /* 0110110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xfe, /* 1111111 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xce, /* 1100111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 147 0x93 '“' */ + 0x10, /* 0001000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 148 0x94 '”' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 149 0x95 '•' */ + 0xc0, /* 1100000 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 150 0x96 '–' */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 151 0x97 '—' */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 152 0x98 '˜' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x7c, /* 0111110 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x70, /* 0111000 */ + + /* 153 0x99 '™' */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 154 0x9a 'š' */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 155 0x9b '›' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x7c, /* 0111110 */ + 0xcc, /* 1100110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0x7c, /* 0111110 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 156 0x9c 'œ' */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0x64, /* 0110010 */ + 0x60, /* 0110000 */ + 0xf0, /* 1111000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0xe6, /* 1110011 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 157 0x9d '' */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0xfc, /* 1111110 */ + 0x30, /* 0011000 */ + 0xfc, /* 1111110 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 158 0x9e 'ž' */ + 0xf8, /* 1111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xf8, /* 1111100 */ + 0xc4, /* 1100010 */ + 0xcc, /* 1100110 */ + 0xde, /* 1101111 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xc6, /* 1100011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 159 0x9f 'Ÿ' */ + 0x1c, /* 0001110 */ + 0x36, /* 0011011 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xfc, /* 1111110 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xb0, /* 1011000 */ + 0xe0, /* 1110000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 160 0xa0 ' ' */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0x0c, /* 0000110 */ + 0x7c, /* 0111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 161 0xa1 '¡' */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0x00, /* 0000000 */ + 0x70, /* 0111000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 162 0xa2 '¢' */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 163 0xa3 '£' */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 164 0xa4 '¤' */ + 0x00, /* 0000000 */ + 0x76, /* 0111011 */ + 0xdc, /* 1101110 */ + 0x00, /* 0000000 */ + 0xb8, /* 1011100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 0111011 */ + 0xdc, /* 1101110 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xec, /* 1110110 */ + 0xec, /* 1110110 */ + 0xfc, /* 1111110 */ + 0xdc, /* 1101110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 166 0xa6 '¦' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0x7c, /* 0111110 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 167 0xa7 '§' */ + 0x00, /* 0000000 */ + 0x70, /* 0111000 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0x70, /* 0111000 */ + 0x00, /* 0000000 */ + 0xf8, /* 1111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 168 0xa8 '¨' */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xc0, /* 1100000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 171 0xab '«' */ + 0x60, /* 0110000 */ + 0xe0, /* 1110000 */ + 0x62, /* 0110001 */ + 0x66, /* 0110011 */ + 0x6c, /* 0110110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xc0, /* 1100000 */ + 0xb8, /* 1011100 */ + 0x4c, /* 0100110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x7c, /* 0111110 */ + + /* 172 0xac '¬' */ + 0x60, /* 0110000 */ + 0xe0, /* 1110000 */ + 0x62, /* 0110001 */ + 0x66, /* 0110011 */ + 0x6c, /* 0110110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x6c, /* 0110110 */ + 0xdc, /* 1101110 */ + 0xb4, /* 1011010 */ + 0x7e, /* 0111111 */ + 0x0c, /* 0000110 */ + 0x0c, /* 0000110 */ + 0x00, /* 0000000 */ + + /* 173 0xad '­' */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0x78, /* 0111100 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 174 0xae '®' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x36, /* 0011011 */ + 0x6c, /* 0110110 */ + 0xd8, /* 1101100 */ + 0x6c, /* 0110110 */ + 0x36, /* 0011011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xd8, /* 1101100 */ + 0x6c, /* 0110110 */ + 0x36, /* 0011011 */ + 0x6c, /* 0110110 */ + 0xd8, /* 1101100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 176 0xb0 '°' */ + 0x88, /* 1000100 */ + 0x22, /* 0010001 */ + 0x88, /* 1000100 */ + 0x22, /* 0010001 */ + 0x88, /* 1000100 */ + 0x22, /* 0010001 */ + 0x88, /* 1000100 */ + 0x22, /* 0010001 */ + 0x88, /* 1000100 */ + 0x22, /* 0010001 */ + 0x88, /* 1000100 */ + 0x22, /* 0010001 */ + 0x88, /* 1000100 */ + 0x22, /* 0010001 */ + + /* 177 0xb1 '±' */ + 0x54, /* 0101010 */ + 0xaa, /* 1010101 */ + 0x54, /* 0101010 */ + 0xaa, /* 1010101 */ + 0x54, /* 0101010 */ + 0xaa, /* 1010101 */ + 0x54, /* 0101010 */ + 0xaa, /* 1010101 */ + 0x54, /* 0101010 */ + 0xaa, /* 1010101 */ + 0x54, /* 0101010 */ + 0xaa, /* 1010101 */ + 0x54, /* 0101010 */ + 0xaa, /* 1010101 */ + + /* 178 0xb2 '²' */ + 0xee, /* 1110111 */ + 0xba, /* 1011101 */ + 0xee, /* 1110111 */ + 0xba, /* 1011101 */ + 0xee, /* 1110111 */ + 0xba, /* 1011101 */ + 0xee, /* 1110111 */ + 0xba, /* 1011101 */ + 0xee, /* 1110111 */ + 0xba, /* 1011101 */ + 0xee, /* 1110111 */ + 0xba, /* 1011101 */ + 0xee, /* 1110111 */ + 0xba, /* 1011101 */ + + /* 179 0xb3 '³' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 180 0xb4 '´' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xf0, /* 1111000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 181 0xb5 'µ' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xf0, /* 1111000 */ + 0x30, /* 0011000 */ + 0xf0, /* 1111000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 182 0xb6 '¶' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xec, /* 1110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xf0, /* 1111000 */ + 0x30, /* 0011000 */ + 0xf0, /* 1111000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 185 0xb9 '¹' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xec, /* 1110110 */ + 0x0c, /* 0000110 */ + 0xec, /* 1110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 186 0xba 'º' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x0c, /* 0000110 */ + 0xec, /* 1110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 188 0xbc '¼' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xec, /* 1110110 */ + 0x0c, /* 0000110 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 189 0xbd '½' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 190 0xbe '¾' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xf0, /* 1111000 */ + 0x30, /* 0011000 */ + 0xf0, /* 1111000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xf0, /* 1111000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 192 0xc0 'À' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x3e, /* 0011111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 193 0xc1 'Á' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 195 0xc3 'Ã' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x3e, /* 0011111 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 197 0xc5 'Å' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xfe, /* 1111111 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 198 0xc6 'Æ' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x3e, /* 0011111 */ + 0x30, /* 0011000 */ + 0x3e, /* 0011111 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 199 0xc7 'Ç' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6e, /* 0110111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 200 0xc8 'È' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6e, /* 0110111 */ + 0x60, /* 0110000 */ + 0x7e, /* 0111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x7e, /* 0111111 */ + 0x60, /* 0110000 */ + 0x6e, /* 0110111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 202 0xca 'Ê' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xee, /* 1110111 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0xee, /* 1110111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 204 0xcc 'Ì' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6e, /* 0110111 */ + 0x60, /* 0110000 */ + 0x6e, /* 0110111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 206 0xce 'Î' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xee, /* 1110111 */ + 0x00, /* 0000000 */ + 0xee, /* 1110111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 207 0xcf 'Ï' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 208 0xd0 'Ð' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 211 0xd3 'Ó' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x7e, /* 0111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 212 0xd4 'Ô' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x3e, /* 0011111 */ + 0x30, /* 0011000 */ + 0x3e, /* 0011111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x3e, /* 0011111 */ + 0x30, /* 0011000 */ + 0x3e, /* 0011111 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x7e, /* 0111111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 215 0xd7 '×' */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xfe, /* 1111111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + + /* 216 0xd8 'Ø' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xfe, /* 1111111 */ + 0x30, /* 0011000 */ + 0xfe, /* 1111111 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 217 0xd9 'Ù' */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xf0, /* 1111000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x3e, /* 0011111 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 219 0xdb 'Û' */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + + /* 221 0xdd 'Ý' */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + 0xe0, /* 1110000 */ + + /* 222 0xde 'Þ' */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + 0x1e, /* 0001111 */ + + /* 223 0xdf 'ß' */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x76, /* 0111011 */ + 0xdc, /* 1101110 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0xdc, /* 1101110 */ + 0x76, /* 0111011 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 225 0xe1 'á' */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xd8, /* 1101100 */ + 0xcc, /* 1100110 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 226 0xe2 'â' */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfe, /* 1111111 */ + 0xfe, /* 1111111 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 228 0xe4 'ä' */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x7e, /* 0111111 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0x70, /* 0111000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xf8, /* 1111100 */ + 0xc0, /* 1100000 */ + 0xc0, /* 1100000 */ + 0x80, /* 1000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x76, /* 0111011 */ + 0xdc, /* 1101110 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 232 0xe8 'è' */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x30, /* 0011000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x30, /* 0011000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 233 0xe9 'é' */ + 0x00, /* 0000000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xfc, /* 1111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x6c, /* 0110110 */ + 0x38, /* 0011100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 234 0xea 'ê' */ + 0x00, /* 0000000 */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0xc6, /* 1100011 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0xee, /* 1110111 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 235 0xeb 'ë' */ + 0x00, /* 0000000 */ + 0x3c, /* 0011110 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x7c, /* 0111110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x78, /* 0111100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x7c, /* 0111110 */ + 0xd6, /* 1101011 */ + 0xd6, /* 1101011 */ + 0xd6, /* 1101011 */ + 0x7c, /* 0111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 237 0xed 'í' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x06, /* 0000011 */ + 0x0c, /* 0000110 */ + 0x7c, /* 0111110 */ + 0xd6, /* 1101011 */ + 0xd6, /* 1101011 */ + 0xe6, /* 1110011 */ + 0x7c, /* 0111110 */ + 0x60, /* 0110000 */ + 0xc0, /* 1100000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 238 0xee 'î' */ + 0x00, /* 0000000 */ + 0x1c, /* 0001110 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x7c, /* 0111110 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x1c, /* 0001110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0xcc, /* 1100110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 241 0xf1 'ñ' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0xfc, /* 1111110 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 242 0xf2 'ò' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x0c, /* 0000110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 243 0xf3 'ó' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x60, /* 0110000 */ + 0xc0, /* 1100000 */ + 0x60, /* 0110000 */ + 0x30, /* 0011000 */ + 0x18, /* 0001100 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 244 0xf4 'ô' */ + 0x00, /* 0000000 */ + 0x1c, /* 0001110 */ + 0x36, /* 0011011 */ + 0x36, /* 0011011 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0x70, /* 0111000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x76, /* 0111011 */ + 0xdc, /* 1101110 */ + 0x00, /* 0000000 */ + 0x76, /* 0111011 */ + 0xdc, /* 1101110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 248 0xf8 'ø' */ + 0x38, /* 0011100 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x38, /* 0011100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x30, /* 0011000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 251 0xfb 'û' */ + 0x1e, /* 0001111 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0x18, /* 0001100 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0xd8, /* 1101100 */ + 0x78, /* 0111100 */ + 0x38, /* 0011100 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 252 0xfc 'ü' */ + 0xd8, /* 1101100 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x6c, /* 0110110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 253 0xfd 'ý' */ + 0x78, /* 0111100 */ + 0xcc, /* 1100110 */ + 0x18, /* 0001100 */ + 0x30, /* 0011000 */ + 0x64, /* 0110010 */ + 0xfc, /* 1111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x7c, /* 0111110 */ + 0x7c, /* 0111110 */ + 0x7c, /* 0111110 */ + 0x7c, /* 0111110 */ + 0x7c, /* 0111110 */ + 0x7c, /* 0111110 */ + 0x7c, /* 0111110 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + 0x00, /* 0000000 */ + +}; + + +struct font_desc font_7x14 = { + FONT7x14_IDX, + "7x14", + 7, + 14, + fontdata_7x14, + 0 +}; diff --git a/drivers/video/console/font_sun12x22.c b/drivers/video/console/font_sun12x22.c index 05215d0..c7bd967 100644 --- a/drivers/video/console/font_sun12x22.c +++ b/drivers/video/console/font_sun12x22.c @@ -29,24 +29,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 1 0x01 '^A' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x1f, 0xc0, /* 000111111100 */ + 0x30, 0x60, /* 001100000110 */ + 0x65, 0x30, /* 011001010011 */ + 0x6d, 0xb0, /* 011011011011 */ + 0x60, 0x30, /* 011000000011 */ + 0x62, 0x30, /* 011000100011 */ + 0x62, 0x30, /* 011000100011 */ + 0x60, 0x30, /* 011000000011 */ + 0x6f, 0xb0, /* 011011111011 */ + 0x67, 0x30, /* 011001110011 */ + 0x30, 0x60, /* 001100000110 */ + 0x1f, 0xc0, /* 000111111100 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -54,24 +53,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 2 0x02 '^B' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x1f, 0xc0, /* 000111111100 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x7a, 0xf0, /* 011110101111 */ + 0x72, 0x70, /* 011100100111 */ + 0x7f, 0xf0, /* 011111111111 */ + 0x7d, 0xf0, /* 011111011111 */ + 0x7d, 0xf0, /* 011111011111 */ + 0x7f, 0xf0, /* 011111111111 */ + 0x70, 0x70, /* 011100000111 */ + 0x78, 0xf0, /* 011110001111 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x1f, 0xc0, /* 000111111100 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -79,24 +77,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 3 0x03 '^C' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x19, 0x80, /* 000110011000 */ 0x3f, 0xc0, /* 001111111100 */ + 0x7f, 0xe0, /* 011111111110 */ 0x3f, 0xc0, /* 001111111100 */ 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -104,24 +101,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 4 0x04 '^D' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x02, 0x00, /* 000000100000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x1f, 0xc0, /* 000111111100 */ + 0x1f, 0xc0, /* 000111111100 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x1f, 0xc0, /* 000111111100 */ + 0x1f, 0xc0, /* 000111111100 */ + 0x0f, 0x80, /* 000011111000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x07, 0x00, /* 000001110000 */ + 0x02, 0x00, /* 000000100000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -129,24 +125,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 5 0x05 '^E' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x02, 0x00, /* 000000100000 */ + 0x07, 0x00, /* 000001110000 */ + 0x07, 0x00, /* 000001110000 */ + 0x02, 0x00, /* 000000100000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x3d, 0xe0, /* 001111011110 */ + 0x3d, 0xe0, /* 001111011110 */ + 0x1a, 0xc0, /* 000110101100 */ + 0x02, 0x00, /* 000000100000 */ + 0x07, 0x00, /* 000001110000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x1f, 0xc0, /* 000111111100 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -154,23 +149,22 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 6 0x06 '^F' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x1f, 0x80, /* 000111111000 */ 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x36, 0xc0, /* 001101101100 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x1f, 0x80, /* 000111111000 */ 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -179,24 +173,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 7 0x07 '^G' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x06, 0x00, /* 000001100000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x1f, 0x80, /* 000111111000 */ 0x3f, 0xc0, /* 001111111100 */ 0x3f, 0xc0, /* 001111111100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -204,49 +197,47 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 8 0x08 '^H' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xf9, 0xf0, /* 111110011111 */ + 0xf0, 0xf0, /* 111100001111 */ + 0xf0, 0xf0, /* 111100001111 */ + 0xe0, 0x70, /* 111000000111 */ + 0xe0, 0x70, /* 111000000111 */ + 0xc0, 0x30, /* 110000000011 */ + 0xc0, 0x30, /* 110000000011 */ + 0xe0, 0x70, /* 111000000111 */ + 0xe0, 0x70, /* 111000000111 */ + 0xf0, 0xf0, /* 111100001111 */ + 0xf0, 0xf0, /* 111100001111 */ + 0xf9, 0xf0, /* 111110011111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ /* 9 0x09 '^I' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x06, 0x00, /* 000001100000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -254,74 +245,71 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 10 0x0a '^J' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xf9, 0xf0, /* 111110011111 */ + 0xf0, 0xf0, /* 111100001111 */ + 0xf0, 0xf0, /* 111100001111 */ + 0xe6, 0x70, /* 111001100111 */ + 0xe6, 0x70, /* 111001100111 */ + 0xcf, 0x30, /* 110011110011 */ + 0xcf, 0x30, /* 110011110011 */ + 0xe6, 0x70, /* 111001100111 */ + 0xe6, 0x70, /* 111001100111 */ + 0xf0, 0xf0, /* 111100001111 */ + 0xf0, 0xf0, /* 111100001111 */ + 0xf9, 0xf0, /* 111110011111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ /* 11 0x0b '^K' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x0f, 0xe0, /* 000011111110 */ + 0x0f, 0xe0, /* 000011111110 */ + 0x01, 0xe0, /* 000000011110 */ + 0x03, 0x60, /* 000000110110 */ + 0x06, 0x60, /* 000001100110 */ + 0x1e, 0x00, /* 000111100000 */ + 0x33, 0x00, /* 001100110000 */ + 0x33, 0x00, /* 001100110000 */ + 0x61, 0x80, /* 011000011000 */ + 0x61, 0x80, /* 011000011000 */ + 0x33, 0x00, /* 001100110000 */ + 0x33, 0x00, /* 001100110000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x0c, 0x00, /* 000011000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ /* 12 0x0c '^L' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x06, 0x00, /* 000001100000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x19, 0x80, /* 000110011000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ 0x3f, 0xc0, /* 001111111100 */ 0x3f, 0xc0, /* 001111111100 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -329,149 +317,143 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 13 0x0d '^M' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x0f, 0xe0, /* 000011111110 */ + 0x0c, 0x60, /* 000011000110 */ + 0x0c, 0x60, /* 000011000110 */ + 0x0f, 0xe0, /* 000011111110 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x3c, 0x00, /* 001111000000 */ + 0x7c, 0x00, /* 011111000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x30, 0x00, /* 001100000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ /* 14 0x0e '^N' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x1f, 0xe0, /* 000111111110 */ + 0x18, 0x60, /* 000110000110 */ + 0x18, 0x60, /* 000110000110 */ + 0x1f, 0xe0, /* 000111111110 */ + 0x18, 0x60, /* 000110000110 */ + 0x18, 0x60, /* 000110000110 */ + 0x18, 0x60, /* 000110000110 */ + 0x18, 0x60, /* 000110000110 */ + 0x18, 0x60, /* 000110000110 */ + 0x18, 0x60, /* 000110000110 */ + 0x19, 0xe0, /* 000110011110 */ + 0x1b, 0xe0, /* 000110111110 */ + 0x1b, 0xc0, /* 000110111100 */ + 0x79, 0x80, /* 011110011000 */ + 0xf8, 0x00, /* 111110000000 */ + 0xf0, 0x00, /* 111100000000 */ + 0x60, 0x00, /* 011000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ /* 15 0x0f '^O' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x18, 0xc0, /* 000110001100 */ + 0x0d, 0x80, /* 000011011000 */ + 0x6d, 0xb0, /* 011011011011 */ + 0x3d, 0xe0, /* 001111011110 */ 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - - /* 16 0x10 '^P' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ + 0x3d, 0xe0, /* 001111011110 */ + 0x6d, 0xb0, /* 011011011011 */ + 0x0d, 0x80, /* 000011011000 */ + 0x18, 0xc0, /* 000110001100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + + /* 16 0x10 '^P' */ 0x00, 0x00, /* 000000000000 */ + 0x00, 0x20, /* 000000000010 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0xe0, /* 000000001110 */ + 0x01, 0xe0, /* 000000011110 */ + 0x03, 0xe0, /* 000000111110 */ + 0x07, 0xe0, /* 000001111110 */ + 0x0f, 0xe0, /* 000011111110 */ + 0x1f, 0xe0, /* 000111111110 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x1f, 0xe0, /* 000111111110 */ + 0x0f, 0xe0, /* 000011111110 */ + 0x07, 0xe0, /* 000001111110 */ + 0x03, 0xe0, /* 000000111110 */ + 0x01, 0xe0, /* 000000011110 */ + 0x00, 0xe0, /* 000000001110 */ + 0x00, 0x60, /* 000000000110 */ + 0x00, 0x20, /* 000000000010 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ /* 17 0x11 '^Q' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x40, 0x00, /* 010000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x70, 0x00, /* 011100000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x7c, 0x00, /* 011111000000 */ + 0x7e, 0x00, /* 011111100000 */ + 0x7f, 0x00, /* 011111110000 */ + 0x7f, 0x80, /* 011111111000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x7f, 0x80, /* 011111111000 */ + 0x7f, 0x00, /* 011111110000 */ + 0x7e, 0x00, /* 011111100000 */ + 0x7c, 0x00, /* 011111000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x70, 0x00, /* 011100000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x40, 0x00, /* 010000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ /* 18 0x12 '^R' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x3f, 0x80, /* 001111111000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x04, 0x00, /* 000001000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -551,99 +533,95 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 22 0x16 '^V' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - - /* 23 0x17 '^W' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - /* 24 0x18 '^X' */ - /* FIXME */ + /* 23 0x17 '^W' */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x3f, 0x80, /* 001111111000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x04, 0x00, /* 000001000000 */ 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + + /* 24 0x18 '^X' */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - - /* 25 0x19 '^Y' */ - /* FIXME */ + 0x04, 0x00, /* 000001000000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + + /* 25 0x19 '^Y' */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x3f, 0x80, /* 001111111000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x04, 0x00, /* 000001000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -651,24 +629,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 26 0x1a '^Z' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x08, 0x00, /* 000010000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x38, 0x00, /* 001110000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0xff, 0xe0, /* 111111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x38, 0x00, /* 001110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x08, 0x00, /* 000010000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -676,24 +653,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 27 0x1b '^[' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x01, 0x00, /* 000000010000 */ + 0x01, 0x80, /* 000000011000 */ + 0x01, 0xc0, /* 000000011100 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xf0, /* 011111111111 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x01, 0xc0, /* 000000011100 */ + 0x01, 0x80, /* 000000011000 */ + 0x01, 0x00, /* 000000010000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -701,24 +677,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 28 0x1c '^\' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x3f, 0xe0, /* 001111111110 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -726,24 +701,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 29 0x1d '^]' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x09, 0x00, /* 000010010000 */ + 0x19, 0x80, /* 000110011000 */ + 0x39, 0xc0, /* 001110011100 */ + 0x7f, 0xe0, /* 011111111110 */ + 0xff, 0xf0, /* 111111111111 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x39, 0xc0, /* 001110011100 */ + 0x19, 0x80, /* 000110011000 */ + 0x09, 0x00, /* 000010010000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -751,24 +725,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 30 0x1e '^^' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -776,24 +749,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 31 0x1f '^_' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x3f, 0x80, /* 001111111000 */ + 0x3f, 0x80, /* 001111111000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x04, 0x00, /* 000001000000 */ + 0x04, 0x00, /* 000001000000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -3081,29 +3053,28 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 127 0x7f '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0xff, 0xf0, /* 111111111111 */ + 0xff, 0xf0, /* 111111111111 */ + 0x00, 0x00, /* 000000000000 */ /* 128 0x80 '.' */ 0x00, 0x00, /* 000000000000 */ @@ -3826,24 +3797,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 158 0x9e '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x7f, 0x80, /* 011111111000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0x60, /* 001100000110 */ + 0x30, 0x60, /* 001100000110 */ + 0x30, 0x60, /* 001100000110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x37, 0x80, /* 001101111000 */ + 0x30, 0x00, /* 001100000000 */ + 0x33, 0x00, /* 001100110000 */ + 0x37, 0x80, /* 001101111000 */ + 0x33, 0x00, /* 001100110000 */ + 0x33, 0x00, /* 001100110000 */ + 0x33, 0x30, /* 001100110011 */ + 0x31, 0xe0, /* 001100011110 */ + 0x78, 0xc0, /* 011110001100 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -3851,28 +3821,27 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 159 0x9f '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x00, 0xc0, /* 000000001100 */ + 0x01, 0xe0, /* 000000011110 */ + 0x03, 0x30, /* 000000110011 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x7f, 0xc0, /* 011111111100 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xcc, 0x00, /* 110011000000 */ + 0x78, 0x00, /* 011110000000 */ + 0x30, 0x00, /* 001100000000 */ 0x00, 0x00, /* 000000000000 */ /* 160 0xa0 '.' */ @@ -4092,24 +4061,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 169 0xa9 '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x3f, 0xc0, /* 001111111100 */ 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5413,24 +5381,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 224 0xe0 '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x60, /* 000011110110 */ + 0x13, 0xe0, /* 000100111110 */ + 0x21, 0xc0, /* 001000011100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x70, 0x80, /* 011100001000 */ + 0x39, 0xc0, /* 001110011100 */ + 0x1f, 0x60, /* 000111110110 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5462,24 +5429,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 226 0xe2 '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x3f, 0xe0, /* 001111111110 */ + 0x30, 0x60, /* 001100000110 */ + 0x30, 0x60, /* 001100000110 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5487,49 +5453,47 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 227 0xe3 '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - - /* 228 0xe4 '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + + /* 228 0xe4 '.' */ 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x60, 0x60, /* 011000000110 */ + 0x30, 0x60, /* 001100000110 */ + 0x30, 0x00, /* 001100000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x60, /* 001100000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5537,24 +5501,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 229 0xe5 '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x07, 0xe0, /* 000001111110 */ + 0x0f, 0xe0, /* 000011111110 */ + 0x13, 0x80, /* 000100111000 */ + 0x21, 0xc0, /* 001000011100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x60, 0xc0, /* 011000001100 */ + 0x70, 0x80, /* 011100001000 */ + 0x39, 0x00, /* 001110010000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5586,24 +5549,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 231 0xe7 '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x19, 0x80, /* 000110011000 */ 0x3f, 0xc0, /* 001111111100 */ + 0x66, 0x60, /* 011001100110 */ + 0x66, 0x60, /* 011001100110 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5611,24 +5573,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 232 0xe8 '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x19, 0x80, /* 000110011000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x19, 0x80, /* 000110011000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5636,24 +5597,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 233 0xe9 '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x0f, 0x00, /* 000011110000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x1f, 0x80, /* 000111111000 */ + 0x0f, 0x00, /* 000011110000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5661,24 +5621,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 234 0xea '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x1f, 0x00, /* 000111110000 */ + 0x31, 0x80, /* 001100011000 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x19, 0x80, /* 000110011000 */ + 0x19, 0x80, /* 000110011000 */ + 0xd9, 0xb0, /* 110110011011 */ + 0x79, 0xe0, /* 011110011110 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5686,24 +5645,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 235 0xeb '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x07, 0x80, /* 000001111000 */ + 0x0c, 0xc0, /* 000011001100 */ + 0x18, 0x60, /* 000110000110 */ + 0x18, 0x00, /* 000110000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x0f, 0x80, /* 000011111000 */ + 0x11, 0xc0, /* 000100011100 */ + 0x20, 0xe0, /* 001000001110 */ + 0x60, 0x60, /* 011000000110 */ + 0x60, 0x60, /* 011000000110 */ + 0x70, 0x40, /* 011100000100 */ + 0x38, 0x80, /* 001110001000 */ + 0x1f, 0x00, /* 000111110000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5711,74 +5669,71 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 236 0xec '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x39, 0xc0, /* 001110011100 */ + 0x6f, 0x60, /* 011011110110 */ + 0x66, 0x60, /* 011001100110 */ + 0xc6, 0x30, /* 110001100011 */ + 0xc6, 0x30, /* 110001100011 */ + 0x66, 0x60, /* 011001100110 */ + 0x6f, 0x60, /* 011011110110 */ + 0x39, 0xc0, /* 001110011100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - - /* 237 0xed '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + + /* 237 0xed '.' */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x00, 0xc0, /* 000000001100 */ + 0x00, 0xc0, /* 000000001100 */ + 0x01, 0x80, /* 000000011000 */ + 0x01, 0x80, /* 000000011000 */ + 0x3b, 0xc0, /* 001110111100 */ + 0x6f, 0x60, /* 011011110110 */ + 0x66, 0x60, /* 011001100110 */ + 0xc6, 0x30, /* 110001100011 */ + 0xc6, 0x30, /* 110001100011 */ + 0x66, 0x60, /* 011001100110 */ + 0x6f, 0x60, /* 011011110110 */ + 0x3d, 0xc0, /* 001111011100 */ + 0x18, 0x00, /* 000110000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x30, 0x00, /* 001100000000 */ + 0x30, 0x00, /* 001100000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ /* 238 0xee '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x01, 0xc0, /* 000000011100 */ + 0x03, 0x00, /* 000000110000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x1f, 0xc0, /* 000111111100 */ + 0x18, 0x00, /* 000110000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x03, 0x00, /* 000000110000 */ + 0x01, 0xc0, /* 000000011100 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5786,24 +5741,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 239 0xef '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x0f, 0x00, /* 000011110000 */ + 0x1f, 0x80, /* 000111111000 */ + 0x39, 0xc0, /* 001110011100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ + 0x30, 0xc0, /* 001100001100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5811,24 +5765,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 240 0xf0 '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5860,24 +5813,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 242 0xf2 '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x60, 0x00, /* 011000000000 */ + 0x38, 0x00, /* 001110000000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x03, 0x80, /* 000000111000 */ + 0x00, 0xe0, /* 000000001110 */ + 0x00, 0xe0, /* 000000001110 */ + 0x03, 0x80, /* 000000111000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x38, 0x00, /* 001110000000 */ + 0x60, 0x00, /* 011000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5885,24 +5837,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 243 0xf3 '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x00, 0x60, /* 000000000110 */ + 0x01, 0xc0, /* 000000011100 */ + 0x07, 0x00, /* 000001110000 */ + 0x1c, 0x00, /* 000111000000 */ + 0x70, 0x00, /* 011100000000 */ + 0x70, 0x00, /* 011100000000 */ + 0x1c, 0x00, /* 000111000000 */ + 0x07, 0x00, /* 000001110000 */ + 0x01, 0xc0, /* 000000011100 */ + 0x00, 0x60, /* 000000000110 */ 0x00, 0x00, /* 000000000000 */ + 0x7f, 0xe0, /* 011111111110 */ + 0x7f, 0xe0, /* 011111111110 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -5910,54 +5861,52 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 244 0xf4 '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x03, 0x80, /* 000000111000 */ + 0x07, 0xc0, /* 000001111100 */ + 0x0c, 0x60, /* 000011000110 */ + 0x0c, 0x60, /* 000011000110 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ + 0x0c, 0x00, /* 000011000000 */ /* 245 0xf5 '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x1c, 0x00, /* 000111000000 */ + 0x3e, 0x00, /* 001111100000 */ + 0x63, 0x00, /* 011000110000 */ + 0x63, 0x00, /* 011000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ + 0x03, 0x00, /* 000000110000 */ /* 246 0xf6 '.' */ 0x00, 0x00, /* 000000000000 */ @@ -5984,24 +5933,23 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 247 0xf7 '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x38, 0x00, /* 001110000000 */ + 0x6c, 0x00, /* 011011000000 */ + 0x06, 0x30, /* 000001100011 */ + 0x03, 0x60, /* 000000110110 */ + 0x39, 0xc0, /* 001110011100 */ + 0x6c, 0x00, /* 011011000000 */ + 0x06, 0x30, /* 000001100011 */ + 0x03, 0x60, /* 000000110110 */ + 0x01, 0xc0, /* 000000011100 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -6033,44 +5981,31 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ /* 249 0xf9 '.' */ - /* FIXME */ - 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - - /* 250 0xfa '.' */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x1c, 0x00, /* 000111000000 */ + 0x3e, 0x00, /* 001111100000 */ + 0x3e, 0x00, /* 001111100000 */ + 0x3e, 0x00, /* 001111100000 */ + 0x1c, 0x00, /* 000111000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + + /* 250 0xfa '.' */ 0x00, 0x00, /* 000000000000 */ - 0x06, 0x00, /* 000001100000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x0f, 0x00, /* 000011110000 */ - 0x06, 0x00, /* 000001100000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ @@ -6080,51 +6015,61 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - - /* 251 0xfb '.' */ - /* FIXME */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + 0x18, 0x00, /* 000110000000 */ + 0x3c, 0x00, /* 001111000000 */ + 0x3c, 0x00, /* 001111000000 */ + 0x18, 0x00, /* 000110000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ + + /* 251 0xfb '.' */ 0x00, 0x00, /* 000000000000 */ + 0x07, 0xe0, /* 000001111110 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x06, 0x00, /* 000001100000 */ + 0xc6, 0x00, /* 110001100000 */ + 0x66, 0x00, /* 011001100000 */ + 0x36, 0x00, /* 001101100000 */ + 0x1e, 0x00, /* 000111100000 */ + 0x0e, 0x00, /* 000011100000 */ + 0x06, 0x00, /* 000001100000 */ + 0x02, 0x00, /* 000000100000 */ 0x00, 0x00, /* 000000000000 */ /* 252 0xfc '.' */ - /* FIXME */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x13, 0x80, /* 000100111000 */ + 0x3d, 0xc0, /* 001111011100 */ + 0x18, 0xc0, /* 000110001100 */ + 0x18, 0xc0, /* 000110001100 */ + 0x18, 0xc0, /* 000110001100 */ + 0x18, 0xc0, /* 000110001100 */ + 0x3d, 0xe0, /* 001111011110 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ + 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ - 0x3f, 0xc0, /* 001111111100 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */ diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c index 465d678..e79b297 100644 --- a/drivers/video/console/fonts.c +++ b/drivers/video/console/fonts.c @@ -36,6 +36,10 @@ static struct font_desc *fonts[] = { #undef NO_FONTS &font_vga_6x11, #endif +#ifdef CONFIG_FONT_7x14 +#undef NO_FONTS + &font_7x14, +#endif #ifdef CONFIG_FONT_SUN8x16 #undef NO_FONTS &font_sun_8x16, @@ -44,6 +48,10 @@ static struct font_desc *fonts[] = { #undef NO_FONTS &font_sun_12x22, #endif +#ifdef CONFIG_FONT_10x18 +#undef NO_FONTS + &font_10x18, +#endif #ifdef CONFIG_FONT_ACORN_8x8 #undef NO_FONTS &font_acorn_8x8, diff --git a/include/linux/font.h b/include/linux/font.h index fc2d690..8fc80a7 100644 --- a/include/linux/font.h +++ b/include/linux/font.h @@ -25,19 +25,23 @@ struct font_desc { #define VGA8x16_IDX 1 #define PEARL8x8_IDX 2 #define VGA6x11_IDX 3 -#define SUN8x16_IDX 4 -#define SUN12x22_IDX 5 -#define ACORN8x8_IDX 6 -#define MINI4x6_IDX 7 +#define FONT7x14_IDX 4 +#define FONT10x18_IDX 5 +#define SUN8x16_IDX 6 +#define SUN12x22_IDX 7 +#define ACORN8x8_IDX 8 +#define MINI4x6_IDX 9 extern struct font_desc font_vga_8x8, - font_vga_8x16, - font_pearl_8x8, - font_vga_6x11, - font_sun_8x16, - font_sun_12x22, - font_acorn_8x8, - font_mini_4x6; + font_vga_8x16, + font_pearl_8x8, + font_vga_6x11, + font_7x14, + font_10x18, + font_sun_8x16, + font_sun_12x22, + font_acorn_8x8, + font_mini_4x6; /* Find a font with a specific name */ -- cgit v0.10.2 From f1ab5dac251bb4514607918b0019a3b3f5f5fb48 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Tue, 21 Jun 2005 17:17:07 -0700 Subject: [PATCH] fbdev: stack reduction Shrink the stack when calling the drawing alignment functions. Signed-off-by: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 4eef207..3c73157 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -157,9 +157,9 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, src = buf; } - fb_sysmove_buf_unaligned(info, &info->pixmap, dst, pitch, - src, idx, image.height, - shift_high, shift_low, mod); + fb_pad_unaligned_buffer(dst, pitch, src, idx, + image.height, shift_high, + shift_low, mod); shift_low += mod; dst += (shift_low >= 8) ? width : width - 1; shift_low &= 7; @@ -175,8 +175,7 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, src = buf; } - fb_sysmove_buf_aligned(info, &info->pixmap, dst, pitch, - src, idx, image.height); + fb_pad_aligned_buffer(dst, pitch, src, idx, image.height); dst += width; } } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 78907a8..6f871a8b 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -78,9 +78,7 @@ EXPORT_SYMBOL(fb_get_color_depth); /* * Data padding functions. */ -void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, - u32 height) +void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height) { int i; @@ -90,12 +88,10 @@ void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, dst += d_pitch; } } -EXPORT_SYMBOL(fb_sysmove_buf_aligned); +EXPORT_SYMBOL(fb_pad_aligned_buffer); -void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 idx, - u32 height, u32 shift_high, u32 shift_low, - u32 mod) +void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height, + u32 shift_high, u32 shift_low, u32 mod) { u8 mask = (u8) (0xfff << shift_high), tmp; int i, j; @@ -122,7 +118,7 @@ void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, dst += d_pitch; } } -EXPORT_SYMBOL(fb_sysmove_buf_unaligned); +EXPORT_SYMBOL(fb_pad_unaligned_buffer); /* * we need to lock this section since fb_cursor diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 47733f5..266ff5d 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -516,9 +516,9 @@ static struct backlight_controller nvidia_backlight_controller = { static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8, u16 bg, u16 fg, u32 w, u32 h) { + u32 *data = (u32 *) data8; int i, j, k = 0; u32 b, tmp; - u32 *data = (u32 *) data8; w = (w + 1) & ~1; @@ -890,11 +890,11 @@ static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor) { struct nvidia_par *par = info->par; u8 data[MAX_CURS * MAX_CURS / 8]; - u16 fg, bg; int i, set = cursor->set; + u16 fg, bg; if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS) - return soft_cursor(info, cursor); + return -ENXIO; NVShowHideCursor(par, 0); @@ -931,21 +931,18 @@ static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor) if (src) { switch (cursor->rop) { case ROP_XOR: - for (i = 0; i < s_pitch * cursor->image.height; - i++) + for (i = 0; i < s_pitch * cursor->image.height; i++) src[i] = dat[i] ^ msk[i]; break; case ROP_COPY: default: - for (i = 0; i < s_pitch * cursor->image.height; - i++) + for (i = 0; i < s_pitch * cursor->image.height; i++) src[i] = dat[i] & msk[i]; break; } - fb_sysmove_buf_aligned(info, &info->pixmap, data, - d_pitch, src, s_pitch, - cursor->image.height); + fb_pad_aligned_buffer(data, d_pitch, src, s_pitch, + cursor->image.height); bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) | ((info->cmap.green[bg_idx] & 0xf8) << 2) | diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index b0c886d..7540f60 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -1582,12 +1582,11 @@ static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor) { struct riva_par *par = (struct riva_par *) info->par; u8 data[MAX_CURS * MAX_CURS/8]; - u16 fg, bg; int i, set = cursor->set; + u16 fg, bg; - if (cursor->image.width > MAX_CURS || - cursor->image.height > MAX_CURS) - return soft_cursor(info, cursor); + if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS) + return -ENXIO; par->riva.ShowHideCursor(&par->riva, 0); @@ -1625,21 +1624,18 @@ static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor) if (src) { switch (cursor->rop) { case ROP_XOR: - for (i = 0; i < s_pitch * cursor->image.height; - i++) + for (i = 0; i < s_pitch * cursor->image.height; i++) src[i] = dat[i] ^ msk[i]; break; case ROP_COPY: default: - for (i = 0; i < s_pitch * cursor->image.height; - i++) + for (i = 0; i < s_pitch * cursor->image.height; i++) src[i] = dat[i] & msk[i]; break; } - fb_sysmove_buf_aligned(info, &info->pixmap, data, - d_pitch, src, s_pitch, - cursor->image.height); + fb_pad_aligned_buffer(data, d_pitch, src, s_pitch, + cursor->image.height); bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) | ((info->cmap.green[bg_idx] & 0xf8) << 2) | diff --git a/drivers/video/softcursor.c b/drivers/video/softcursor.c index a6c5ca8..229c4bc 100644 --- a/drivers/video/softcursor.c +++ b/drivers/video/softcursor.c @@ -58,13 +58,10 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) } else memcpy(src, image->data, dsize); - fb_sysmove_buf_aligned(info, &info->pixmap, dst, d_pitch, src, - s_pitch, image->height); - + fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height); image->data = dst; info->fbops->fb_imageblit(info, image); kfree(src); - return 0; } diff --git a/include/linux/fb.h b/include/linux/fb.h index e149428..bc24bee 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -816,12 +816,9 @@ extern int unregister_framebuffer(struct fb_info *fb_info); extern int fb_prepare_logo(struct fb_info *fb_info); extern int fb_show_logo(struct fb_info *fb_info); extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size); -extern void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 idx, +extern void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height, u32 shift_high, u32 shift_low, u32 mod); -extern void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, - u32 height); +extern void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height); extern void fb_set_suspend(struct fb_info *info, int state); extern int fb_get_color_depth(struct fb_var_screeninfo *var); extern int fb_get_options(char *name, char **option); -- cgit v0.10.2 From 58a606431a704b5c240c1429a5526fac81c9800a Mon Sep 17 00:00:00 2001 From: James Simmons Date: Tue, 21 Jun 2005 17:17:08 -0700 Subject: [PATCH] fbdev: fill in the access_align field. Several drivers miss filling in the access_align field. So this patch has them fill it in. Signed-off-by: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 6f871a8b..2222de6 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1034,7 +1034,7 @@ register_framebuffer(struct fb_info *fb_info) fb_info->pixmap.size = FBPIXMAPSIZE; fb_info->pixmap.buf_align = 1; fb_info->pixmap.scan_align = 1; - fb_info->pixmap.access_align = 4; + fb_info->pixmap.access_align = 32; fb_info->pixmap.flags = FB_PIXMAP_DEFAULT; } } diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index a9a618f..7513fb9 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -1885,6 +1885,7 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev, memset(info->pixmap.addr, 0, 8*1024); info->pixmap.size = 8*1024; info->pixmap.buf_align = 8; + info->pixmap.access_align = 32; info->pixmap.flags = FB_PIXMAP_SYSTEM; if ((err = i810_allocate_pci_resource(par, entry))) { diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 448c908..298bc9c 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -1091,6 +1091,7 @@ intelfb_set_fbinfo(struct intelfb_info *dinfo) info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; + info->pixmap.access_align = 32; info->pixmap.flags = FB_PIXMAP_SYSTEM; if (intelfb_init_var(dinfo)) diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 266ff5d..b2e6b24 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -1345,6 +1345,7 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info) info->pixmap.scan_align = 4; info->pixmap.buf_align = 4; + info->pixmap.access_align = 32; info->pixmap.size = 8 * 1024; info->pixmap.flags = FB_PIXMAP_SYSTEM; diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 7540f60..6a9e183 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -1723,6 +1723,7 @@ static int __devinit riva_set_fbinfo(struct fb_info *info) info->pixmap.size = 8 * 1024; info->pixmap.buf_align = 4; + info->pixmap.access_align = 32; info->pixmap.flags = FB_PIXMAP_SYSTEM; info->var.yres_virtual = -1; NVTRACE_LEAVE(); diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 03d74e8..8fadcda 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -1897,7 +1897,7 @@ static int __devinit savage_init_fb_info (struct fb_info *info, info->pixmap.size = 8*1024; info->pixmap.scan_align = 4; info->pixmap.buf_align = 4; - info->pixmap.access_align = 4; + info->pixmap.access_align = 32; fb_alloc_cmap (&info->cmap, NR_PALETTE, 0); info->flags |= FBINFO_HWACCEL_COPYAREA | -- cgit v0.10.2 From 6ea9c07c6c6d1c14d9757dd8470dc4c85bbe9f28 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:09 -0700 Subject: [PATCH] md: cause md/raid1 to "repack" working devices when number of drives is changed i.e. missing or failed drives are moved to the end of the list. The means a 3 drive md array with the first drive missing can be shrunk to a two drive array. Currently that isn't possible. Also, the "last_used" device number might be out-of-range after the number of devices is reduced, so we set it to 0. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 1db5de5..4947f59 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1349,17 +1349,26 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks) * We allocate a new r1bio_pool if we can. * Then raise a device barrier and wait until all IO stops. * Then resize conf->mirrors and swap in the new r1bio pool. + * + * At the same time, we "pack" the devices so that all the missing + * devices have the higher raid_disk numbers. */ mempool_t *newpool, *oldpool; struct pool_info *newpoolinfo; mirror_info_t *newmirrors; conf_t *conf = mddev_to_conf(mddev); + int cnt; - int d; + int d, d2; - for (d= raid_disks; d < conf->raid_disks; d++) - if (conf->mirrors[d].rdev) + if (raid_disks < conf->raid_disks) { + cnt=0; + for (d= 0; d < conf->raid_disks; d++) + if (conf->mirrors[d].rdev) + cnt++; + if (cnt > raid_disks) return -EBUSY; + } newpoolinfo = kmalloc(sizeof(*newpoolinfo), GFP_KERNEL); if (!newpoolinfo) @@ -1390,8 +1399,12 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks) /* ok, everything is stopped */ oldpool = conf->r1bio_pool; conf->r1bio_pool = newpool; - for (d=0; d < raid_disks && d < conf->raid_disks; d++) - newmirrors[d] = conf->mirrors[d]; + + for (d=d2=0; d < conf->raid_disks; d++) + if (conf->mirrors[d].rdev) { + conf->mirrors[d].rdev->raid_disk = d2; + newmirrors[d2++].rdev = conf->mirrors[d].rdev; + } kfree(conf->mirrors); conf->mirrors = newmirrors; kfree(conf->poolinfo); @@ -1400,6 +1413,7 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks) mddev->degraded += (raid_disks - conf->raid_disks); conf->raid_disks = mddev->raid_disks = raid_disks; + conf->last_used = 0; /* just make sure it is in-range */ spin_lock_irq(&conf->resync_lock); conf->barrier--; spin_unlock_irq(&conf->resync_lock); -- cgit v0.10.2 From c361777fb9347a4d16b82272f7d3b234e94bef2d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:10 -0700 Subject: [PATCH] md: make sure recovery happens when add_new_disk is used for hot_add Currently if add_new_disk is used to hot-add a drive to a degraded array, recovery doesn't start ... because we didn't tell it to. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/md.c b/drivers/md/md.c index d899204..60835df 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2083,6 +2083,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) err = bind_rdev_to_array(rdev, mddev); if (err) export_rdev(rdev); + + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); if (mddev->thread) md_wakeup_thread(mddev->thread); return err; -- cgit v0.10.2 From fca4d848f0e6fafdc2b25f8a0cf1e76935f13ac2 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:11 -0700 Subject: [PATCH] md: merge md_enter_safemode into md_check_recovery md_enter_safemode checks if it is time to mark the md superblock as 'clean'. i.e. if all writes have completed and a suitable delay has passed. This is currently called from md_handle_safemode which in-turn is called (almost) every time md_check_recovery is called, and from the end of md_do_sync which causes the mddev->thread to run, which will always call md_check_recovery as well. So it doesn't need to be a separate function and fits quite well into md_check_recovery. The "almost" is because multipathd calls md_check_recovery but not md_handle_safemode. This is OK because the code from md_enter_safemode is a no-op if mddev->safemode == 0, which it always is for a multipathd (providing we don't allow it to be set to 2 on a signal...) Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/md.c b/drivers/md/md.c index 60835df..c842e34 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3203,37 +3203,6 @@ void md_write_end(mddev_t *mddev) } } -static inline void md_enter_safemode(mddev_t *mddev) -{ - if (!mddev->safemode) return; - if (mddev->safemode == 2 && - (atomic_read(&mddev->writes_pending) || mddev->in_sync || - mddev->recovery_cp != MaxSector)) - return; /* avoid the lock */ - mddev_lock_uninterruptible(mddev); - if (mddev->safemode && !atomic_read(&mddev->writes_pending) && - !mddev->in_sync && mddev->recovery_cp == MaxSector) { - mddev->in_sync = 1; - md_update_sb(mddev); - } - mddev_unlock(mddev); - - if (mddev->safemode == 1) - mddev->safemode = 0; -} - -void md_handle_safemode(mddev_t *mddev) -{ - if (signal_pending(current)) { - printk(KERN_INFO "md: %s in immediate safe mode\n", - mdname(mddev)); - mddev->safemode = 2; - flush_signals(current); - } - md_enter_safemode(mddev); -} - - static DECLARE_WAIT_QUEUE_HEAD(resync_wait); #define SYNC_MARKS 10 @@ -3449,7 +3418,6 @@ static void md_do_sync(mddev_t *mddev) mddev->recovery_cp = MaxSector; } - md_enter_safemode(mddev); skip: mddev->curr_resync = 0; wake_up(&resync_wait); @@ -3490,14 +3458,37 @@ void md_check_recovery(mddev_t *mddev) if (mddev->ro) return; + + if (signal_pending(current)) { + if (mddev->pers->sync_request) { + printk(KERN_INFO "md: %s in immediate safe mode\n", + mdname(mddev)); + mddev->safemode = 2; + } + flush_signals(current); + } + if ( ! ( mddev->sb_dirty || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || - test_bit(MD_RECOVERY_DONE, &mddev->recovery) + test_bit(MD_RECOVERY_DONE, &mddev->recovery) || + (mddev->safemode == 1) || + (mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending) + && !mddev->in_sync && mddev->recovery_cp == MaxSector) )) return; + if (mddev_trylock(mddev)==0) { int spares =0; + + if (mddev->safemode && !atomic_read(&mddev->writes_pending) && + !mddev->in_sync && mddev->recovery_cp == MaxSector) { + mddev->in_sync = 1; + mddev->sb_dirty = 1; + } + if (mddev->safemode == 1) + mddev->safemode = 0; + if (mddev->sb_dirty) md_update_sb(mddev); if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) && @@ -3741,7 +3732,6 @@ EXPORT_SYMBOL(md_error); EXPORT_SYMBOL(md_done_sync); EXPORT_SYMBOL(md_write_start); EXPORT_SYMBOL(md_write_end); -EXPORT_SYMBOL(md_handle_safemode); EXPORT_SYMBOL(md_register_thread); EXPORT_SYMBOL(md_unregister_thread); EXPORT_SYMBOL(md_wakeup_thread); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 4947f59..b34ad56 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -931,7 +931,6 @@ static void raid1d(mddev_t *mddev) mdk_rdev_t *rdev; md_check_recovery(mddev); - md_handle_safemode(mddev); for (;;) { char b[BDEVNAME_SIZE]; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 3c37be6..9ae2150 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1216,7 +1216,6 @@ static void raid10d(mddev_t *mddev) mdk_rdev_t *rdev; md_check_recovery(mddev); - md_handle_safemode(mddev); for (;;) { char b[BDEVNAME_SIZE]; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 3cb11ac..63b1c59 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1546,7 +1546,6 @@ static void raid5d (mddev_t *mddev) PRINTK("+++ raid5d active\n"); md_check_recovery(mddev); - md_handle_safemode(mddev); handled = 0; spin_lock_irq(&conf->device_lock); diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 908edd7..9d0e0e4 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -1705,7 +1705,6 @@ static void raid6d (mddev_t *mddev) PRINTK("+++ raid6d active\n"); md_check_recovery(mddev); - md_handle_safemode(mddev); handled = 0; spin_lock_irq(&conf->device_lock); -- cgit v0.10.2 From 06d91a5fe0b50c9060e70bdf7786f8a3c66249db Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:12 -0700 Subject: [PATCH] md: improve locking on 'safemode' and move superblock writes When md marks the superblock dirty before a write, it calls generic_make_request (to write the superblock) from within generic_make_request (to write the first dirty block), which could cause problems later. With this patch, the superblock write is always done by the helper thread, and write request are delayed until that write completes. Also, the locking around marking the array dirty and writing the superblock is improved to avoid possible races. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/md.c b/drivers/md/md.c index c842e34..177d2a7 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -218,6 +218,8 @@ static mddev_t * mddev_find(dev_t unit) INIT_LIST_HEAD(&new->all_mddevs); init_timer(&new->safemode_timer); atomic_set(&new->active, 1); + bio_list_init(&new->write_list); + spin_lock_init(&new->write_lock); new->queue = blk_alloc_queue(GFP_KERNEL); if (!new->queue) { @@ -1251,9 +1253,11 @@ static void md_update_sb(mddev_t * mddev) int err, count = 100; struct list_head *tmp; mdk_rdev_t *rdev; + int sync_req; - mddev->sb_dirty = 0; repeat: + spin_lock(&mddev->write_lock); + sync_req = mddev->in_sync; mddev->utime = get_seconds(); mddev->events ++; @@ -1272,8 +1276,12 @@ repeat: * do not write anything to disk if using * nonpersistent superblocks */ - if (!mddev->persistent) + if (!mddev->persistent) { + mddev->sb_dirty = 0; + spin_unlock(&mddev->write_lock); return; + } + spin_unlock(&mddev->write_lock); dprintk(KERN_INFO "md: updating %s RAID superblock on device (in sync %d)\n", @@ -1304,6 +1312,15 @@ repeat: printk(KERN_ERR \ "md: excessive errors occurred during superblock update, exiting\n"); } + spin_lock(&mddev->write_lock); + if (mddev->in_sync != sync_req) { + /* have to write it out again */ + spin_unlock(&mddev->write_lock); + goto repeat; + } + mddev->sb_dirty = 0; + spin_unlock(&mddev->write_lock); + } /* @@ -3178,19 +3195,31 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok) } -void md_write_start(mddev_t *mddev) +/* md_write_start(mddev, bi) + * If we need to update some array metadata (e.g. 'active' flag + * in superblock) before writing, queue bi for later writing + * and return 0, else return 1 and it will be written now + */ +int md_write_start(mddev_t *mddev, struct bio *bi) { - if (!atomic_read(&mddev->writes_pending)) { - mddev_lock_uninterruptible(mddev); - if (mddev->in_sync) { - mddev->in_sync = 0; - del_timer(&mddev->safemode_timer); - md_update_sb(mddev); - } - atomic_inc(&mddev->writes_pending); - mddev_unlock(mddev); - } else - atomic_inc(&mddev->writes_pending); + if (bio_data_dir(bi) != WRITE) + return 1; + + atomic_inc(&mddev->writes_pending); + spin_lock(&mddev->write_lock); + if (mddev->in_sync == 0 && mddev->sb_dirty == 0) { + spin_unlock(&mddev->write_lock); + return 1; + } + bio_list_add(&mddev->write_list, bi); + + if (mddev->in_sync) { + mddev->in_sync = 0; + mddev->sb_dirty = 1; + } + spin_unlock(&mddev->write_lock); + md_wakeup_thread(mddev->thread); + return 0; } void md_write_end(mddev_t *mddev) @@ -3472,6 +3501,7 @@ void md_check_recovery(mddev_t *mddev) mddev->sb_dirty || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || test_bit(MD_RECOVERY_DONE, &mddev->recovery) || + mddev->write_list.head || (mddev->safemode == 1) || (mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending) && !mddev->in_sync && mddev->recovery_cp == MaxSector) @@ -3480,7 +3510,9 @@ void md_check_recovery(mddev_t *mddev) if (mddev_trylock(mddev)==0) { int spares =0; + struct bio *blist; + spin_lock(&mddev->write_lock); if (mddev->safemode && !atomic_read(&mddev->writes_pending) && !mddev->in_sync && mddev->recovery_cp == MaxSector) { mddev->in_sync = 1; @@ -3488,9 +3520,22 @@ void md_check_recovery(mddev_t *mddev) } if (mddev->safemode == 1) mddev->safemode = 0; + blist = bio_list_get(&mddev->write_list); + spin_unlock(&mddev->write_lock); if (mddev->sb_dirty) md_update_sb(mddev); + + while (blist) { + struct bio *b = blist; + blist = blist->bi_next; + b->bi_next = NULL; + generic_make_request(b); + /* we already counted this, so need to un-count */ + md_write_end(mddev); + } + + if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) && !test_bit(MD_RECOVERY_DONE, &mddev->recovery)) { /* resync/recovery still happening */ diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index b34ad56..3f1280b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -530,6 +530,8 @@ static int make_request(request_queue_t *q, struct bio * bio) * thread has put up a bar for new requests. * Continue immediately if no resync is active currently. */ + if (md_write_start(mddev, bio)==0) + return 0; spin_lock_irq(&conf->resync_lock); wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock, ); conf->nr_pending++; @@ -611,7 +613,7 @@ static int make_request(request_queue_t *q, struct bio * bio) rcu_read_unlock(); atomic_set(&r1_bio->remaining, 1); - md_write_start(mddev); + for (i = 0; i < disks; i++) { struct bio *mbio; if (!r1_bio->bios[i]) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 9ae2150..bfc9f52 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -700,6 +700,9 @@ static int make_request(request_queue_t *q, struct bio * bio) return 0; } + if (md_write_start(mddev, bio) == 0) + return 0; + /* * Register the new request and wait if the reconstruction * thread has put up a bar for new requests. @@ -774,7 +777,7 @@ static int make_request(request_queue_t *q, struct bio * bio) rcu_read_unlock(); atomic_set(&r10_bio->remaining, 1); - md_write_start(mddev); + for (i = 0; i < conf->copies; i++) { struct bio *mbio; int d = r10_bio->devs[i].devnum; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 63b1c59..677ce49 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1411,6 +1411,9 @@ static int make_request (request_queue_t *q, struct bio * bi) sector_t logical_sector, last_sector; struct stripe_head *sh; + if (md_write_start(mddev, bi)==0) + return 0; + if (bio_data_dir(bi)==WRITE) { disk_stat_inc(mddev->gendisk, writes); disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bi)); @@ -1423,8 +1426,7 @@ static int make_request (request_queue_t *q, struct bio * bi) last_sector = bi->bi_sector + (bi->bi_size>>9); bi->bi_next = NULL; bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ - if ( bio_data_dir(bi) == WRITE ) - md_write_start(mddev); + for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { DEFINE_WAIT(w); diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 9d0e0e4..fede16c 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -1570,6 +1570,9 @@ static int make_request (request_queue_t *q, struct bio * bi) sector_t logical_sector, last_sector; struct stripe_head *sh; + if (md_write_start(mddev, bi)==0) + return 0; + if (bio_data_dir(bi)==WRITE) { disk_stat_inc(mddev->gendisk, writes); disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bi)); @@ -1583,8 +1586,7 @@ static int make_request (request_queue_t *q, struct bio * bi) bi->bi_next = NULL; bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ - if ( bio_data_dir(bi) == WRITE ) - md_write_start(mddev); + for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { DEFINE_WAIT(w); diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h index a6a67d1..cfde8f4 100644 --- a/include/linux/raid/md.h +++ b/include/linux/raid/md.h @@ -69,7 +69,7 @@ extern mdk_thread_t * md_register_thread (void (*run) (mddev_t *mddev), extern void md_unregister_thread (mdk_thread_t *thread); extern void md_wakeup_thread(mdk_thread_t *thread); extern void md_check_recovery(mddev_t *mddev); -extern void md_write_start(mddev_t *mddev); +extern int md_write_start(mddev_t *mddev, struct bio *bi); extern void md_write_end(mddev_t *mddev); extern void md_handle_safemode(mddev_t *mddev); extern void md_done_sync(mddev_t *mddev, int blocks, int ok); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index c9a0d40..d92db54 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -15,6 +15,9 @@ #ifndef _MD_K_H #define _MD_K_H +/* and dm-bio-list.h is not under include/linux because.... ??? */ +#include "../../../drivers/md/dm-bio-list.h" + #define MD_RESERVED 0UL #define LINEAR 1UL #define RAID0 2UL @@ -252,6 +255,10 @@ struct mddev_s atomic_t recovery_active; /* blocks scheduled, but not written */ wait_queue_head_t recovery_wait; sector_t recovery_cp; + + spinlock_t write_lock; + struct bio_list write_list; + unsigned int safemode; /* if set, update "clean" superblock * when no writes pending. */ -- cgit v0.10.2 From 57afd89f98a990747445f01c458ecae64263b2f8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:13 -0700 Subject: [PATCH] md: improve the interface to sync_request 1/ change the return value (which is number-of-sectors synced) from 'int' to 'sector_t'. The number of sectors is usually easily small enough to fit in an int, but if resync needs to abort, it may want to return the total number of remaining sectors, which could be large. Also errors cannot be returned as negative numbers now, so use 0 instead 2/ Add a 'skipped' return parameter to allow the array to report that it skipped the sectors. This allows md to take this into account in the speed calculations. Currently there is no important skipping, but the bitmap-based-resync that is coming will use this. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/md.c b/drivers/md/md.c index 177d2a7..fa608a1 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3241,12 +3241,13 @@ static void md_do_sync(mddev_t *mddev) mddev_t *mddev2; unsigned int currspeed = 0, window; - sector_t max_sectors,j; + sector_t max_sectors,j, io_sectors; unsigned long mark[SYNC_MARKS]; sector_t mark_cnt[SYNC_MARKS]; int last_mark,m; struct list_head *tmp; sector_t last_check; + int skipped = 0; /* just incase thread restarts... */ if (test_bit(MD_RECOVERY_DONE, &mddev->recovery)) @@ -3312,7 +3313,7 @@ static void md_do_sync(mddev_t *mddev) if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) /* resync follows the size requested by the personality, - * which default to physical size, but can be virtual size + * which defaults to physical size, but can be virtual size */ max_sectors = mddev->resync_max_sectors; else @@ -3331,9 +3332,10 @@ static void md_do_sync(mddev_t *mddev) j = mddev->recovery_cp; else j = 0; + io_sectors = 0; for (m = 0; m < SYNC_MARKS; m++) { mark[m] = jiffies; - mark_cnt[m] = j; + mark_cnt[m] = io_sectors; } last_mark = 0; mddev->resync_mark = mark[last_mark]; @@ -3358,21 +3360,29 @@ static void md_do_sync(mddev_t *mddev) } while (j < max_sectors) { - int sectors; + sector_t sectors; - sectors = mddev->pers->sync_request(mddev, j, currspeed < sysctl_speed_limit_min); - if (sectors < 0) { + skipped = 0; + sectors = mddev->pers->sync_request(mddev, j, &skipped, + currspeed < sysctl_speed_limit_min); + if (sectors == 0) { set_bit(MD_RECOVERY_ERR, &mddev->recovery); goto out; } - atomic_add(sectors, &mddev->recovery_active); + + if (!skipped) { /* actual IO requested */ + io_sectors += sectors; + atomic_add(sectors, &mddev->recovery_active); + } + j += sectors; if (j>1) mddev->curr_resync = j; - if (last_check + window > j || j == max_sectors) + + if (last_check + window > io_sectors || j == max_sectors) continue; - last_check = j; + last_check = io_sectors; if (test_bit(MD_RECOVERY_INTR, &mddev->recovery) || test_bit(MD_RECOVERY_ERR, &mddev->recovery)) @@ -3386,7 +3396,7 @@ static void md_do_sync(mddev_t *mddev) mddev->resync_mark = mark[next]; mddev->resync_mark_cnt = mark_cnt[next]; mark[next] = jiffies; - mark_cnt[next] = j - atomic_read(&mddev->recovery_active); + mark_cnt[next] = io_sectors - atomic_read(&mddev->recovery_active); last_mark = next; } @@ -3413,7 +3423,8 @@ static void md_do_sync(mddev_t *mddev) mddev->queue->unplug_fn(mddev->queue); cond_resched(); - currspeed = ((unsigned long)(j-mddev->resync_mark_cnt))/2/((jiffies-mddev->resync_mark)/HZ +1) +1; + currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2 + /((jiffies-mddev->resync_mark)/HZ +1) +1; if (currspeed > sysctl_speed_limit_min) { if ((currspeed > sysctl_speed_limit_max) || @@ -3433,7 +3444,7 @@ static void md_do_sync(mddev_t *mddev) wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active)); /* tell personality that we are finished */ - mddev->pers->sync_request(mddev, max_sectors, 1); + mddev->pers->sync_request(mddev, max_sectors, &skipped, 1); if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && mddev->curr_resync > 2 && diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 3f1280b..3c5c916 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1010,7 +1010,7 @@ static int init_resync(conf_t *conf) * that can be installed to exclude normal IO requests. */ -static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) +static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) { conf_t *conf = mddev_to_conf(mddev); mirror_info_t *mirror; @@ -1023,7 +1023,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) if (!conf->r1buf_pool) if (init_resync(conf)) - return -ENOMEM; + return 0; max_sector = mddev->size << 1; if (sector_nr >= max_sector) { @@ -1107,8 +1107,8 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) /* There is nowhere to write, so all non-sync * drives must be failed - so we are finished */ - int rv = max_sector - sector_nr; - md_done_sync(mddev, rv, 1); + sector_t rv = max_sector - sector_nr; + *skipped = 1; put_buf(r1_bio); rdev_dec_pending(conf->mirrors[disk].rdev, mddev); return rv; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index bfc9f52..8476515 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1321,7 +1321,7 @@ static int init_resync(conf_t *conf) * */ -static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) +static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) { conf_t *conf = mddev_to_conf(mddev); r10bio_t *r10_bio; @@ -1335,7 +1335,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) if (!conf->r10buf_pool) if (init_resync(conf)) - return -ENOMEM; + return 0; skipped: max_sector = mddev->size << 1; @@ -1343,15 +1343,15 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) max_sector = mddev->resync_max_sectors; if (sector_nr >= max_sector) { close_sync(conf); + *skipped = 1; return sectors_skipped; } if (chunks_skipped >= conf->raid_disks) { /* if there has been nothing to do on any drive, * then there is nothing to do at all.. */ - sector_t sec = max_sector - sector_nr; - md_done_sync(mddev, sec, 1); - return sec + sectors_skipped; + *skipped = 1; + return (max_sector - sector_nr) + sectors_skipped; } /* make sure whole request will fit in a chunk - if chunks @@ -1565,17 +1565,22 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) } } + if (sectors_skipped) + /* pretend they weren't skipped, it makes + * no important difference in this case + */ + md_done_sync(mddev, sectors_skipped, 1); + return sectors_skipped + nr_sectors; giveup: /* There is nowhere to write, so all non-sync * drives must be failed, so try the next chunk... */ { - int sec = max_sector - sector_nr; + sector_t sec = max_sector - sector_nr; sectors_skipped += sec; chunks_skipped ++; sector_nr = max_sector; - md_done_sync(mddev, sec, 1); goto skipped; } } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 677ce49..1ce3f5a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1477,7 +1477,7 @@ static int make_request (request_queue_t *q, struct bio * bi) } /* FIXME go_faster isn't used */ -static int sync_request (mddev_t *mddev, sector_t sector_nr, int go_faster) +static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) { raid5_conf_t *conf = (raid5_conf_t *) mddev->private; struct stripe_head *sh; @@ -1500,8 +1500,8 @@ static int sync_request (mddev_t *mddev, sector_t sector_nr, int go_faster) * nothing we can do. */ if (mddev->degraded >= 1 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { - int rv = (mddev->size << 1) - sector_nr; - md_done_sync(mddev, rv, 1); + sector_t rv = (mddev->size << 1) - sector_nr; + *skipped = 1; return rv; } diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index fede16c..d9c3854 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -1636,7 +1636,7 @@ static int make_request (request_queue_t *q, struct bio * bi) } /* FIXME go_faster isn't used */ -static int sync_request (mddev_t *mddev, sector_t sector_nr, int go_faster) +static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) { raid6_conf_t *conf = (raid6_conf_t *) mddev->private; struct stripe_head *sh; @@ -1659,8 +1659,8 @@ static int sync_request (mddev_t *mddev, sector_t sector_nr, int go_faster) * nothing we can do. */ if (mddev->degraded >= 2 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { - int rv = (mddev->size << 1) - sector_nr; - md_done_sync(mddev, rv, 1); + sector_t rv = (mddev->size << 1) - sector_nr; + *skipped = 1; return rv; } diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index d92db54..bce0032 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -298,7 +298,7 @@ struct mdk_personality_s int (*hot_add_disk) (mddev_t *mddev, mdk_rdev_t *rdev); int (*hot_remove_disk) (mddev_t *mddev, int number); int (*spare_active) (mddev_t *mddev); - int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster); + sector_t (*sync_request)(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster); int (*resize) (mddev_t *mddev, sector_t sectors); int (*reshape) (mddev_t *mddev, int raid_disks); int (*reconfig) (mddev_t *mddev, int layout, int chunk_size); -- cgit v0.10.2 From 32a7627cf3a35396a8e834faf34e38ae9f3b1309 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:14 -0700 Subject: [PATCH] md: optimised resync using Bitmap based intent logging With this patch, the intent to write to some block in the array can be logged to a bitmap file. Each bit represents some number of sectors and is set before any update happens, and only cleared when all writes relating to all sectors are complete. After an unclean shutdown, information in this bitmap can be used to optimise resync - only sectors which could be out-of-sync need to be updated. Also if a drive is removed and then added back into an array, the recovery can make use of the bitmap to optimise reconstruction. This is not implemented in this patch. Currently the bitmap is stored in a file which must (obviously) be stored on a separate device. The patch only provided infrastructure. It does not update any personalities to bitmap intent logging. Md arrays can still be used with no bitmap file. This patch has minimal impact on such arrays. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/Makefile b/drivers/md/Makefile index 90de9c1..d3efedf 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -7,6 +7,7 @@ dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \ dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o dm-snapshot-objs := dm-snap.o dm-exception-store.o dm-mirror-objs := dm-log.o dm-raid1.o +md-mod-objs := md.o bitmap.o raid6-objs := raid6main.o raid6algos.o raid6recov.o raid6tables.o \ raid6int1.o raid6int2.o raid6int4.o \ raid6int8.o raid6int16.o raid6int32.o \ @@ -28,7 +29,7 @@ obj-$(CONFIG_MD_RAID5) += raid5.o xor.o obj-$(CONFIG_MD_RAID6) += raid6.o xor.o obj-$(CONFIG_MD_MULTIPATH) += multipath.o obj-$(CONFIG_MD_FAULTY) += faulty.o -obj-$(CONFIG_BLK_DEV_MD) += md.o +obj-$(CONFIG_BLK_DEV_MD) += md-mod.o obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o obj-$(CONFIG_DM_CRYPT) += dm-crypt.o obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c new file mode 100644 index 0000000..34ffc13 --- /dev/null +++ b/drivers/md/bitmap.c @@ -0,0 +1,1519 @@ +/* + * bitmap.c two-level bitmap (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003 + * + * bitmap_create - sets up the bitmap structure + * bitmap_destroy - destroys the bitmap structure + * + * additions, Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.: + * - added disk storage for bitmap + * - changes to allow various bitmap chunk sizes + * - added bitmap daemon (to asynchronously clear bitmap bits from disk) + */ + +/* + * Still to do: + * + * flush after percent set rather than just time based. (maybe both). + * wait if count gets too high, wake when it drops to half. + * allow bitmap to be mirrored with superblock (before or after...) + * allow hot-add to re-instate a current device. + * allow hot-add of bitmap after quiessing device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* debug macros */ + +#define DEBUG 0 + +#if DEBUG +/* these are for debugging purposes only! */ + +/* define one and only one of these */ +#define INJECT_FAULTS_1 0 /* cause bitmap_alloc_page to fail always */ +#define INJECT_FAULTS_2 0 /* cause bitmap file to be kicked when first bit set*/ +#define INJECT_FAULTS_3 0 /* treat bitmap file as kicked at init time */ +#define INJECT_FAULTS_4 0 /* undef */ +#define INJECT_FAULTS_5 0 /* undef */ +#define INJECT_FAULTS_6 0 + +/* if these are defined, the driver will fail! debug only */ +#define INJECT_FATAL_FAULT_1 0 /* fail kmalloc, causing bitmap_create to fail */ +#define INJECT_FATAL_FAULT_2 0 /* undef */ +#define INJECT_FATAL_FAULT_3 0 /* undef */ +#endif + +//#define DPRINTK PRINTK /* set this NULL to avoid verbose debug output */ +#define DPRINTK(x...) do { } while(0) + +#ifndef PRINTK +# if DEBUG > 0 +# define PRINTK(x...) printk(KERN_DEBUG x) +# else +# define PRINTK(x...) +# endif +#endif + +static inline char * bmname(struct bitmap *bitmap) +{ + return bitmap->mddev ? mdname(bitmap->mddev) : "mdX"; +} + + +/* + * test if the bitmap is active + */ +int bitmap_active(struct bitmap *bitmap) +{ + unsigned long flags; + int res = 0; + + if (!bitmap) + return res; + spin_lock_irqsave(&bitmap->lock, flags); + res = bitmap->flags & BITMAP_ACTIVE; + spin_unlock_irqrestore(&bitmap->lock, flags); + return res; +} + +#define WRITE_POOL_SIZE 256 +/* mempool for queueing pending writes on the bitmap file */ +static void *write_pool_alloc(unsigned int gfp_flags, void *data) +{ + return kmalloc(sizeof(struct page_list), gfp_flags); +} + +static void write_pool_free(void *ptr, void *data) +{ + kfree(ptr); +} + +/* + * just a placeholder - calls kmalloc for bitmap pages + */ +static unsigned char *bitmap_alloc_page(struct bitmap *bitmap) +{ + unsigned char *page; + +#if INJECT_FAULTS_1 + page = NULL; +#else + page = kmalloc(PAGE_SIZE, GFP_NOIO); +#endif + if (!page) + printk("%s: bitmap_alloc_page FAILED\n", bmname(bitmap)); + else + printk("%s: bitmap_alloc_page: allocated page at %p\n", + bmname(bitmap), page); + return page; +} + +/* + * for now just a placeholder -- just calls kfree for bitmap pages + */ +static void bitmap_free_page(struct bitmap *bitmap, unsigned char *page) +{ + PRINTK("%s: bitmap_free_page: free page %p\n", bmname(bitmap), page); + kfree(page); +} + +/* + * check a page and, if necessary, allocate it (or hijack it if the alloc fails) + * + * 1) check to see if this page is allocated, if it's not then try to alloc + * 2) if the alloc fails, set the page's hijacked flag so we'll use the + * page pointer directly as a counter + * + * if we find our page, we increment the page's refcount so that it stays + * allocated while we're using it + */ +static int bitmap_checkpage(struct bitmap *bitmap, unsigned long page, int create) +{ + unsigned char *mappage; + + if (page >= bitmap->pages) { + printk(KERN_ALERT + "%s: invalid bitmap page request: %lu (> %lu)\n", + bmname(bitmap), page, bitmap->pages-1); + return -EINVAL; + } + + + if (bitmap->bp[page].hijacked) /* it's hijacked, don't try to alloc */ + return 0; + + if (bitmap->bp[page].map) /* page is already allocated, just return */ + return 0; + + if (!create) + return -ENOENT; + + spin_unlock_irq(&bitmap->lock); + + /* this page has not been allocated yet */ + + if ((mappage = bitmap_alloc_page(bitmap)) == NULL) { + PRINTK("%s: bitmap map page allocation failed, hijacking\n", + bmname(bitmap)); + /* failed - set the hijacked flag so that we can use the + * pointer as a counter */ + spin_lock_irq(&bitmap->lock); + if (!bitmap->bp[page].map) + bitmap->bp[page].hijacked = 1; + goto out; + } + + /* got a page */ + + spin_lock_irq(&bitmap->lock); + + /* recheck the page */ + + if (bitmap->bp[page].map || bitmap->bp[page].hijacked) { + /* somebody beat us to getting the page */ + bitmap_free_page(bitmap, mappage); + return 0; + } + + /* no page was in place and we have one, so install it */ + + memset(mappage, 0, PAGE_SIZE); + bitmap->bp[page].map = mappage; + bitmap->missing_pages--; +out: + return 0; +} + + +/* if page is completely empty, put it back on the free list, or dealloc it */ +/* if page was hijacked, unmark the flag so it might get alloced next time */ +/* Note: lock should be held when calling this */ +static inline void bitmap_checkfree(struct bitmap *bitmap, unsigned long page) +{ + char *ptr; + + if (bitmap->bp[page].count) /* page is still busy */ + return; + + /* page is no longer in use, it can be released */ + + if (bitmap->bp[page].hijacked) { /* page was hijacked, undo this now */ + bitmap->bp[page].hijacked = 0; + bitmap->bp[page].map = NULL; + return; + } + + /* normal case, free the page */ + +#if 0 +/* actually ... let's not. We will probably need the page again exactly when + * memory is tight and we are flusing to disk + */ + return; +#else + ptr = bitmap->bp[page].map; + bitmap->bp[page].map = NULL; + bitmap->missing_pages++; + bitmap_free_page(bitmap, ptr); + return; +#endif +} + + +/* + * bitmap file handling - read and write the bitmap file and its superblock + */ + +/* copy the pathname of a file to a buffer */ +char *file_path(struct file *file, char *buf, int count) +{ + struct dentry *d; + struct vfsmount *v; + + if (!buf) + return NULL; + + d = file->f_dentry; + v = file->f_vfsmnt; + + buf = d_path(d, v, buf, count); + + return IS_ERR(buf) ? NULL : buf; +} + +/* + * basic page I/O operations + */ + +/* + * write out a page + */ +static int write_page(struct page *page, int wait) +{ + int ret = -ENOMEM; + + lock_page(page); + + if (page->mapping == NULL) + goto unlock_out; + else if (i_size_read(page->mapping->host) < page->index << PAGE_SHIFT) { + ret = -ENOENT; + goto unlock_out; + } + + ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE); + if (!ret) + ret = page->mapping->a_ops->commit_write(NULL, page, 0, + PAGE_SIZE); + if (ret) { +unlock_out: + unlock_page(page); + return ret; + } + + set_page_dirty(page); /* force it to be written out */ + return write_one_page(page, wait); +} + +/* read a page from a file, pinning it into cache, and return bytes_read */ +static struct page *read_page(struct file *file, unsigned long index, + unsigned long *bytes_read) +{ + struct inode *inode = file->f_mapping->host; + struct page *page = NULL; + loff_t isize = i_size_read(inode); + unsigned long end_index = isize >> PAGE_CACHE_SHIFT; + + PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_CACHE_SIZE, + (unsigned long long)index << PAGE_CACHE_SHIFT); + + page = read_cache_page(inode->i_mapping, index, + (filler_t *)inode->i_mapping->a_ops->readpage, file); + if (IS_ERR(page)) + goto out; + wait_on_page_locked(page); + if (!PageUptodate(page) || PageError(page)) { + page_cache_release(page); + page = ERR_PTR(-EIO); + goto out; + } + + if (index > end_index) /* we have read beyond EOF */ + *bytes_read = 0; + else if (index == end_index) /* possible short read */ + *bytes_read = isize & ~PAGE_CACHE_MASK; + else + *bytes_read = PAGE_CACHE_SIZE; /* got a full page */ +out: + if (IS_ERR(page)) + printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n", + (int)PAGE_CACHE_SIZE, + (unsigned long long)index << PAGE_CACHE_SHIFT, + PTR_ERR(page)); + return page; +} + +/* + * bitmap file superblock operations + */ + +/* update the event counter and sync the superblock to disk */ +int bitmap_update_sb(struct bitmap *bitmap) +{ + bitmap_super_t *sb; + unsigned long flags; + + if (!bitmap || !bitmap->mddev) /* no bitmap for this array */ + return 0; + spin_lock_irqsave(&bitmap->lock, flags); + if (!bitmap->sb_page) { /* no superblock */ + spin_unlock_irqrestore(&bitmap->lock, flags); + return 0; + } + page_cache_get(bitmap->sb_page); + spin_unlock_irqrestore(&bitmap->lock, flags); + sb = (bitmap_super_t *)kmap(bitmap->sb_page); + sb->events = cpu_to_le64(bitmap->mddev->events); + if (!bitmap->mddev->degraded) + sb->events_cleared = cpu_to_le64(bitmap->mddev->events); + kunmap(bitmap->sb_page); + write_page(bitmap->sb_page, 0); + return 0; +} + +/* print out the bitmap file superblock */ +void bitmap_print_sb(struct bitmap *bitmap) +{ + bitmap_super_t *sb; + + if (!bitmap || !bitmap->sb_page) + return; + sb = (bitmap_super_t *)kmap(bitmap->sb_page); + printk(KERN_DEBUG "%s: bitmap file superblock:\n", bmname(bitmap)); + printk(KERN_DEBUG " magic: %08x\n", le32_to_cpu(sb->magic)); + printk(KERN_DEBUG " version: %d\n", le32_to_cpu(sb->version)); + printk(KERN_DEBUG " uuid: %08x.%08x.%08x.%08x\n", + *(__u32 *)(sb->uuid+0), + *(__u32 *)(sb->uuid+4), + *(__u32 *)(sb->uuid+8), + *(__u32 *)(sb->uuid+12)); + printk(KERN_DEBUG " events: %llu\n", + (unsigned long long) le64_to_cpu(sb->events)); + printk(KERN_DEBUG "events_clred: %llu\n", + (unsigned long long) le64_to_cpu(sb->events_cleared)); + printk(KERN_DEBUG " state: %08x\n", le32_to_cpu(sb->state)); + printk(KERN_DEBUG " chunksize: %d B\n", le32_to_cpu(sb->chunksize)); + printk(KERN_DEBUG "daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep)); + printk(KERN_DEBUG " sync size: %llu KB\n", le64_to_cpu(sb->sync_size)); + kunmap(bitmap->sb_page); +} + +/* read the superblock from the bitmap file and initialize some bitmap fields */ +static int bitmap_read_sb(struct bitmap *bitmap) +{ + char *reason = NULL; + bitmap_super_t *sb; + unsigned long chunksize, daemon_sleep; + unsigned long bytes_read; + unsigned long long events; + int err = -EINVAL; + + /* page 0 is the superblock, read it... */ + bitmap->sb_page = read_page(bitmap->file, 0, &bytes_read); + if (IS_ERR(bitmap->sb_page)) { + err = PTR_ERR(bitmap->sb_page); + bitmap->sb_page = NULL; + return err; + } + + sb = (bitmap_super_t *)kmap(bitmap->sb_page); + + if (bytes_read < sizeof(*sb)) { /* short read */ + printk(KERN_INFO "%s: bitmap file superblock truncated\n", + bmname(bitmap)); + err = -ENOSPC; + goto out; + } + + chunksize = le32_to_cpu(sb->chunksize); + daemon_sleep = le32_to_cpu(sb->daemon_sleep); + + /* verify that the bitmap-specific fields are valid */ + if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) + reason = "bad magic"; + else if (sb->version != cpu_to_le32(BITMAP_MAJOR)) + reason = "unrecognized superblock version"; + else if (chunksize < 512 || chunksize > (1024 * 1024 * 4)) + reason = "bitmap chunksize out of range (512B - 4MB)"; + else if ((1 << ffz(~chunksize)) != chunksize) + reason = "bitmap chunksize not a power of 2"; + else if (daemon_sleep < 1 || daemon_sleep > 15) + reason = "daemon sleep period out of range"; + if (reason) { + printk(KERN_INFO "%s: invalid bitmap file superblock: %s\n", + bmname(bitmap), reason); + goto out; + } + + /* keep the array size field of the bitmap superblock up to date */ + sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors); + + if (!bitmap->mddev->persistent) + goto success; + + /* + * if we have a persistent array superblock, compare the + * bitmap's UUID and event counter to the mddev's + */ + if (memcmp(sb->uuid, bitmap->mddev->uuid, 16)) { + printk(KERN_INFO "%s: bitmap superblock UUID mismatch\n", + bmname(bitmap)); + goto out; + } + events = le64_to_cpu(sb->events); + if (events < bitmap->mddev->events) { + printk(KERN_INFO "%s: bitmap file is out of date (%llu < %llu) " + "-- forcing full recovery\n", bmname(bitmap), events, + (unsigned long long) bitmap->mddev->events); + sb->state |= BITMAP_STALE; + } +success: + /* assign fields using values from superblock */ + bitmap->chunksize = chunksize; + bitmap->daemon_sleep = daemon_sleep; + bitmap->flags |= sb->state; + bitmap->events_cleared = le64_to_cpu(sb->events_cleared); + err = 0; +out: + kunmap(bitmap->sb_page); + if (err) + bitmap_print_sb(bitmap); + return err; +} + +enum bitmap_mask_op { + MASK_SET, + MASK_UNSET +}; + +/* record the state of the bitmap in the superblock */ +static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, + enum bitmap_mask_op op) +{ + bitmap_super_t *sb; + unsigned long flags; + + spin_lock_irqsave(&bitmap->lock, flags); + if (!bitmap || !bitmap->sb_page) { /* can't set the state */ + spin_unlock_irqrestore(&bitmap->lock, flags); + return; + } + page_cache_get(bitmap->sb_page); + spin_unlock_irqrestore(&bitmap->lock, flags); + sb = (bitmap_super_t *)kmap(bitmap->sb_page); + switch (op) { + case MASK_SET: sb->state |= bits; + break; + case MASK_UNSET: sb->state &= ~bits; + break; + default: BUG(); + } + kunmap(bitmap->sb_page); + page_cache_release(bitmap->sb_page); +} + +/* + * general bitmap file operations + */ + +/* calculate the index of the page that contains this bit */ +static inline unsigned long file_page_index(unsigned long chunk) +{ + return CHUNK_BIT_OFFSET(chunk) >> PAGE_BIT_SHIFT; +} + +/* calculate the (bit) offset of this bit within a page */ +static inline unsigned long file_page_offset(unsigned long chunk) +{ + return CHUNK_BIT_OFFSET(chunk) & (PAGE_BITS - 1); +} + +/* + * return a pointer to the page in the filemap that contains the given bit + * + * this lookup is complicated by the fact that the bitmap sb might be exactly + * 1 page (e.g., x86) or less than 1 page -- so the bitmap might start on page + * 0 or page 1 + */ +static inline struct page *filemap_get_page(struct bitmap *bitmap, + unsigned long chunk) +{ + return bitmap->filemap[file_page_index(chunk) - file_page_index(0)]; +} + + +static void bitmap_file_unmap(struct bitmap *bitmap) +{ + struct page **map, *sb_page; + unsigned long *attr; + int pages; + unsigned long flags; + + spin_lock_irqsave(&bitmap->lock, flags); + map = bitmap->filemap; + bitmap->filemap = NULL; + attr = bitmap->filemap_attr; + bitmap->filemap_attr = NULL; + pages = bitmap->file_pages; + bitmap->file_pages = 0; + sb_page = bitmap->sb_page; + bitmap->sb_page = NULL; + spin_unlock_irqrestore(&bitmap->lock, flags); + + while (pages--) + if (map[pages]->index != 0) /* 0 is sb_page, release it below */ + page_cache_release(map[pages]); + kfree(map); + kfree(attr); + + if (sb_page) + page_cache_release(sb_page); +} + +static void bitmap_stop_daemons(struct bitmap *bitmap); + +/* dequeue the next item in a page list -- don't call from irq context */ +static struct page_list *dequeue_page(struct bitmap *bitmap, + struct list_head *head) +{ + struct page_list *item = NULL; + + spin_lock(&bitmap->write_lock); + if (list_empty(head)) + goto out; + item = list_entry(head->prev, struct page_list, list); + list_del(head->prev); +out: + spin_unlock(&bitmap->write_lock); + return item; +} + +static void drain_write_queues(struct bitmap *bitmap) +{ + struct list_head *queues[] = { &bitmap->complete_pages, NULL }; + struct list_head *head; + struct page_list *item; + int i; + + for (i = 0; queues[i]; i++) { + head = queues[i]; + while ((item = dequeue_page(bitmap, head))) { + page_cache_release(item->page); + mempool_free(item, bitmap->write_pool); + } + } + + spin_lock(&bitmap->write_lock); + bitmap->writes_pending = 0; /* make sure waiters continue */ + wake_up(&bitmap->write_wait); + spin_unlock(&bitmap->write_lock); +} + +static void bitmap_file_put(struct bitmap *bitmap) +{ + struct file *file; + struct inode *inode; + unsigned long flags; + + spin_lock_irqsave(&bitmap->lock, flags); + file = bitmap->file; + bitmap->file = NULL; + spin_unlock_irqrestore(&bitmap->lock, flags); + + bitmap_stop_daemons(bitmap); + + drain_write_queues(bitmap); + + bitmap_file_unmap(bitmap); + + if (file) { + inode = file->f_mapping->host; + spin_lock(&inode->i_lock); + atomic_set(&inode->i_writecount, 1); /* allow writes again */ + spin_unlock(&inode->i_lock); + fput(file); + } +} + + +/* + * bitmap_file_kick - if an error occurs while manipulating the bitmap file + * then it is no longer reliable, so we stop using it and we mark the file + * as failed in the superblock + */ +static void bitmap_file_kick(struct bitmap *bitmap) +{ + char *path, *ptr = NULL; + + bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET); + bitmap_update_sb(bitmap); + + path = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (path) + ptr = file_path(bitmap->file, path, PAGE_SIZE); + + printk(KERN_ALERT "%s: kicking failed bitmap file %s from array!\n", + bmname(bitmap), ptr ? ptr : ""); + + kfree(path); + + bitmap_file_put(bitmap); + + return; +} + +enum bitmap_page_attr { + BITMAP_PAGE_DIRTY = 1, // there are set bits that need to be synced + BITMAP_PAGE_CLEAN = 2, // there are bits that might need to be cleared + BITMAP_PAGE_NEEDWRITE=4, // there are cleared bits that need to be synced +}; + +static inline void set_page_attr(struct bitmap *bitmap, struct page *page, + enum bitmap_page_attr attr) +{ + bitmap->filemap_attr[page->index] |= attr; +} + +static inline void clear_page_attr(struct bitmap *bitmap, struct page *page, + enum bitmap_page_attr attr) +{ + bitmap->filemap_attr[page->index] &= ~attr; +} + +static inline unsigned long get_page_attr(struct bitmap *bitmap, struct page *page) +{ + return bitmap->filemap_attr[page->index]; +} + +/* + * bitmap_file_set_bit -- called before performing a write to the md device + * to set (and eventually sync) a particular bit in the bitmap file + * + * we set the bit immediately, then we record the page number so that + * when an unplug occurs, we can flush the dirty pages out to disk + */ +static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) +{ + unsigned long bit; + struct page *page; + void *kaddr; + unsigned long chunk = block >> CHUNK_BLOCK_SHIFT(bitmap); + + if (!bitmap->file || !bitmap->filemap) { + return; + } + + page = filemap_get_page(bitmap, chunk); + bit = file_page_offset(chunk); + + + /* make sure the page stays cached until it gets written out */ + if (! (get_page_attr(bitmap, page) & BITMAP_PAGE_DIRTY)) + page_cache_get(page); + + /* set the bit */ + kaddr = kmap_atomic(page, KM_USER0); + set_bit(bit, kaddr); + kunmap_atomic(kaddr, KM_USER0); + PRINTK("set file bit %lu page %lu\n", bit, page->index); + + /* record page number so it gets flushed to disk when unplug occurs */ + set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); + +} + +/* this gets called when the md device is ready to unplug its underlying + * (slave) device queues -- before we let any writes go down, we need to + * sync the dirty pages of the bitmap file to disk */ +int bitmap_unplug(struct bitmap *bitmap) +{ + unsigned long i, attr, flags; + struct page *page; + int wait = 0; + + if (!bitmap) + return 0; + + /* look at each page to see if there are any set bits that need to be + * flushed out to disk */ + for (i = 0; i < bitmap->file_pages; i++) { + spin_lock_irqsave(&bitmap->lock, flags); + if (!bitmap->file || !bitmap->filemap) { + spin_unlock_irqrestore(&bitmap->lock, flags); + return 0; + } + page = bitmap->filemap[i]; + attr = get_page_attr(bitmap, page); + clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); + clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); + if ((attr & BITMAP_PAGE_DIRTY)) + wait = 1; + spin_unlock_irqrestore(&bitmap->lock, flags); + + if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) + write_page(page, 0); + } + if (wait) { /* if any writes were performed, we need to wait on them */ + spin_lock_irq(&bitmap->write_lock); + wait_event_lock_irq(bitmap->write_wait, + bitmap->writes_pending == 0, bitmap->write_lock, + wake_up_process(bitmap->writeback_daemon->tsk)); + spin_unlock_irq(&bitmap->write_lock); + } + return 0; +} + +static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, + unsigned long sectors, int set); +/* * bitmap_init_from_disk -- called at bitmap_create time to initialize + * the in-memory bitmap from the on-disk bitmap -- also, sets up the + * memory mapping of the bitmap file + * Special cases: + * if there's no bitmap file, or if the bitmap file had been + * previously kicked from the array, we mark all the bits as + * 1's in order to cause a full resync. + */ +static int bitmap_init_from_disk(struct bitmap *bitmap) +{ + unsigned long i, chunks, index, oldindex, bit; + struct page *page = NULL, *oldpage = NULL; + unsigned long num_pages, bit_cnt = 0; + struct file *file; + unsigned long bytes, offset, dummy; + int outofdate; + int ret = -ENOSPC; + + chunks = bitmap->chunks; + file = bitmap->file; + + if (!file) { /* no file, dirty all the in-memory bits */ + printk(KERN_INFO "%s: no bitmap file, doing full recovery\n", + bmname(bitmap)); + bitmap_set_memory_bits(bitmap, 0, + chunks << CHUNK_BLOCK_SHIFT(bitmap), 1); + return 0; + } + +#if INJECT_FAULTS_3 + outofdate = 1; +#else + outofdate = bitmap->flags & BITMAP_STALE; +#endif + if (outofdate) + printk(KERN_INFO "%s: bitmap file is out of date, doing full " + "recovery\n", bmname(bitmap)); + + bytes = (chunks + 7) / 8; + num_pages = (bytes + PAGE_SIZE - 1) / PAGE_SIZE; + if (i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) { + printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n", + bmname(bitmap), + (unsigned long) i_size_read(file->f_mapping->host), + bytes + sizeof(bitmap_super_t)); + goto out; + } + num_pages++; + bitmap->filemap = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL); + if (!bitmap->filemap) { + ret = -ENOMEM; + goto out; + } + + bitmap->filemap_attr = kmalloc(sizeof(long) * num_pages, GFP_KERNEL); + if (!bitmap->filemap_attr) { + ret = -ENOMEM; + goto out; + } + + memset(bitmap->filemap_attr, 0, sizeof(long) * num_pages); + + oldindex = ~0L; + + for (i = 0; i < chunks; i++) { + index = file_page_index(i); + bit = file_page_offset(i); + if (index != oldindex) { /* this is a new page, read it in */ + /* unmap the old page, we're done with it */ + if (oldpage != NULL) + kunmap(oldpage); + if (index == 0) { + /* + * if we're here then the superblock page + * contains some bits (PAGE_SIZE != sizeof sb) + * we've already read it in, so just use it + */ + page = bitmap->sb_page; + offset = sizeof(bitmap_super_t); + } else { + page = read_page(file, index, &dummy); + if (IS_ERR(page)) { /* read error */ + ret = PTR_ERR(page); + goto out; + } + offset = 0; + } + oldindex = index; + oldpage = page; + kmap(page); + + if (outofdate) { + /* + * if bitmap is out of date, dirty the + * whole page and write it out + */ + memset(page_address(page) + offset, 0xff, + PAGE_SIZE - offset); + ret = write_page(page, 1); + if (ret) { + kunmap(page); + /* release, page not in filemap yet */ + page_cache_release(page); + goto out; + } + } + + bitmap->filemap[bitmap->file_pages++] = page; + } + if (test_bit(bit, page_address(page))) { + /* if the disk bit is set, set the memory bit */ + bitmap_set_memory_bits(bitmap, + i << CHUNK_BLOCK_SHIFT(bitmap), 1, 1); + bit_cnt++; + } +#if 0 + else + bitmap_set_memory_bits(bitmap, + i << CHUNK_BLOCK_SHIFT(bitmap), 1, 0); +#endif + } + + /* everything went OK */ + ret = 0; + bitmap_mask_state(bitmap, BITMAP_STALE, MASK_UNSET); + + if (page) /* unmap the last page */ + kunmap(page); + + if (bit_cnt) { /* Kick recovery if any bits were set */ + set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery); + md_wakeup_thread(bitmap->mddev->thread); + } + +out: + printk(KERN_INFO "%s: bitmap initialized from disk: " + "read %lu/%lu pages, set %lu bits, status: %d\n", + bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, ret); + + return ret; +} + + +static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) +{ + sector_t chunk = offset >> CHUNK_BLOCK_SHIFT(bitmap); + unsigned long page = chunk >> PAGE_COUNTER_SHIFT; + bitmap->bp[page].count += inc; +/* + if (page == 0) printk("count page 0, offset %llu: %d gives %d\n", + (unsigned long long)offset, inc, bitmap->bp[page].count); +*/ + bitmap_checkfree(bitmap, page); +} +static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, + sector_t offset, int *blocks, + int create); + +/* + * bitmap daemon -- periodically wakes up to clean bits and flush pages + * out to disk + */ + +int bitmap_daemon_work(struct bitmap *bitmap) +{ + unsigned long bit, j; + unsigned long flags; + struct page *page = NULL, *lastpage = NULL; + int err = 0; + int blocks; + int attr; + + if (bitmap == NULL) + return 0; + if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ)) + return 0; + bitmap->daemon_lastrun = jiffies; + + for (j = 0; j < bitmap->chunks; j++) { + bitmap_counter_t *bmc; + spin_lock_irqsave(&bitmap->lock, flags); + if (!bitmap->file || !bitmap->filemap) { + /* error or shutdown */ + spin_unlock_irqrestore(&bitmap->lock, flags); + break; + } + + page = filemap_get_page(bitmap, j); + /* skip this page unless it's marked as needing cleaning */ + if (!((attr=get_page_attr(bitmap, page)) & BITMAP_PAGE_CLEAN)) { + if (attr & BITMAP_PAGE_NEEDWRITE) { + page_cache_get(page); + clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); + } + spin_unlock_irqrestore(&bitmap->lock, flags); + if (attr & BITMAP_PAGE_NEEDWRITE) { + if (write_page(page, 0)) + bitmap_file_kick(bitmap); + page_cache_release(page); + } + continue; + } + + bit = file_page_offset(j); + + if (page != lastpage) { + /* grab the new page, sync and release the old */ + page_cache_get(page); + if (lastpage != NULL) { + if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) { + clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); + spin_unlock_irqrestore(&bitmap->lock, flags); + write_page(lastpage, 0); + } else { + set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); + spin_unlock_irqrestore(&bitmap->lock, flags); + } + kunmap(lastpage); + page_cache_release(lastpage); + if (err) + bitmap_file_kick(bitmap); + } else + spin_unlock_irqrestore(&bitmap->lock, flags); + lastpage = page; + kmap(page); +/* + printk("bitmap clean at page %lu\n", j); +*/ + spin_lock_irqsave(&bitmap->lock, flags); + clear_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); + } + bmc = bitmap_get_counter(bitmap, j << CHUNK_BLOCK_SHIFT(bitmap), + &blocks, 0); + if (bmc) { +/* + if (j < 100) printk("bitmap: j=%lu, *bmc = 0x%x\n", j, *bmc); +*/ + if (*bmc == 2) { + *bmc=1; /* maybe clear the bit next time */ + set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); + } else if (*bmc == 1) { + /* we can clear the bit */ + *bmc = 0; + bitmap_count_page(bitmap, j << CHUNK_BLOCK_SHIFT(bitmap), + -1); + + /* clear the bit */ + clear_bit(bit, page_address(page)); + } + } + spin_unlock_irqrestore(&bitmap->lock, flags); + } + + /* now sync the final page */ + if (lastpage != NULL) { + kunmap(lastpage); + spin_lock_irqsave(&bitmap->lock, flags); + if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) { + clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); + spin_unlock_irqrestore(&bitmap->lock, flags); + write_page(lastpage, 0); + } else { + set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); + spin_unlock_irqrestore(&bitmap->lock, flags); + } + + page_cache_release(lastpage); + } + + return err; +} + +static void daemon_exit(struct bitmap *bitmap, mdk_thread_t **daemon) +{ + mdk_thread_t *dmn; + unsigned long flags; + + /* if no one is waiting on us, we'll free the md thread struct + * and exit, otherwise we let the waiter clean things up */ + spin_lock_irqsave(&bitmap->lock, flags); + if ((dmn = *daemon)) { /* no one is waiting, cleanup and exit */ + *daemon = NULL; + spin_unlock_irqrestore(&bitmap->lock, flags); + kfree(dmn); + complete_and_exit(NULL, 0); /* do_exit not exported */ + } + spin_unlock_irqrestore(&bitmap->lock, flags); +} + +static void bitmap_writeback_daemon(mddev_t *mddev) +{ + struct bitmap *bitmap = mddev->bitmap; + struct page *page; + struct page_list *item; + int err = 0; + + while (1) { + PRINTK("%s: bitmap writeback daemon waiting...\n", bmname(bitmap)); + down_interruptible(&bitmap->write_done); + if (signal_pending(current)) { + printk(KERN_INFO + "%s: bitmap writeback daemon got signal, exiting...\n", + bmname(bitmap)); + break; + } + + PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap)); + /* wait on bitmap page writebacks */ + while ((item = dequeue_page(bitmap, &bitmap->complete_pages))) { + page = item->page; + mempool_free(item, bitmap->write_pool); + PRINTK("wait on page writeback: %p %lu\n", page, bitmap->writes_pending); + wait_on_page_writeback(page); + PRINTK("finished page writeback: %p %lu\n", page, bitmap->writes_pending); + spin_lock(&bitmap->write_lock); + if (!--bitmap->writes_pending) + wake_up(&bitmap->write_wait); + spin_unlock(&bitmap->write_lock); + err = PageError(page); + page_cache_release(page); + if (err) { + printk(KERN_WARNING "%s: bitmap file writeback " + "failed (page %lu): %d\n", + bmname(bitmap), page->index, err); + bitmap_file_kick(bitmap); + goto out; + } + } + } +out: + if (err) { + printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n", + bmname(bitmap), err); + daemon_exit(bitmap, &bitmap->writeback_daemon); + } + return; +} + +static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr, + void (*func)(mddev_t *), char *name) +{ + mdk_thread_t *daemon; + unsigned long flags; + char namebuf[32]; + + spin_lock_irqsave(&bitmap->lock, flags); + *ptr = NULL; + if (!bitmap->file) /* no need for daemon if there's no backing file */ + goto out_unlock; + + spin_unlock_irqrestore(&bitmap->lock, flags); + +#if INJECT_FATAL_FAULT_2 + daemon = NULL; +#else + sprintf(namebuf, "%%s_%s", name); + daemon = md_register_thread(func, bitmap->mddev, namebuf); +#endif + if (!daemon) { + printk(KERN_ERR "%s: failed to start bitmap daemon\n", + bmname(bitmap)); + return -ECHILD; + } + + spin_lock_irqsave(&bitmap->lock, flags); + *ptr = daemon; + + md_wakeup_thread(daemon); /* start it running */ + + PRINTK("%s: %s daemon (pid %d) started...\n", + bmname(bitmap), name, bitmap->daemon->tsk->pid); +out_unlock: + spin_unlock_irqrestore(&bitmap->lock, flags); + return 0; +} + +static int bitmap_start_daemons(struct bitmap *bitmap) +{ + int err = bitmap_start_daemon(bitmap, &bitmap->writeback_daemon, + bitmap_writeback_daemon, "bitmap_wb"); + return err; +} + +static void bitmap_stop_daemon(struct bitmap *bitmap, mdk_thread_t **ptr) +{ + mdk_thread_t *daemon; + unsigned long flags; + + spin_lock_irqsave(&bitmap->lock, flags); + daemon = *ptr; + *ptr = NULL; + spin_unlock_irqrestore(&bitmap->lock, flags); + if (daemon) + md_unregister_thread(daemon); /* destroy the thread */ +} + +static void bitmap_stop_daemons(struct bitmap *bitmap) +{ + /* the daemons can't stop themselves... they'll just exit instead... */ + if (bitmap->writeback_daemon && + current->pid != bitmap->writeback_daemon->tsk->pid) + bitmap_stop_daemon(bitmap, &bitmap->writeback_daemon); +} + +static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, + sector_t offset, int *blocks, + int create) +{ + /* If 'create', we might release the lock and reclaim it. + * The lock must have been taken with interrupts enabled. + * If !create, we don't release the lock. + */ + sector_t chunk = offset >> CHUNK_BLOCK_SHIFT(bitmap); + unsigned long page = chunk >> PAGE_COUNTER_SHIFT; + unsigned long pageoff = (chunk & PAGE_COUNTER_MASK) << COUNTER_BYTE_SHIFT; + sector_t csize; + + if (bitmap_checkpage(bitmap, page, create) < 0) { + csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap)); + *blocks = csize - (offset & (csize- 1)); + return NULL; + } + /* now locked ... */ + + if (bitmap->bp[page].hijacked) { /* hijacked pointer */ + /* should we use the first or second counter field + * of the hijacked pointer? */ + int hi = (pageoff > PAGE_COUNTER_MASK); + csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap) + + PAGE_COUNTER_SHIFT - 1); + *blocks = csize - (offset & (csize- 1)); + return &((bitmap_counter_t *) + &bitmap->bp[page].map)[hi]; + } else { /* page is allocated */ + csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap)); + *blocks = csize - (offset & (csize- 1)); + return (bitmap_counter_t *) + &(bitmap->bp[page].map[pageoff]); + } +} + +int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors) +{ + if (!bitmap) return 0; + while (sectors) { + int blocks; + bitmap_counter_t *bmc; + + spin_lock_irq(&bitmap->lock); + bmc = bitmap_get_counter(bitmap, offset, &blocks, 1); + if (!bmc) { + spin_unlock_irq(&bitmap->lock); + return 0; + } + + switch(*bmc) { + case 0: + bitmap_file_set_bit(bitmap, offset); + bitmap_count_page(bitmap,offset, 1); + blk_plug_device(bitmap->mddev->queue); + /* fall through */ + case 1: + *bmc = 2; + } + if ((*bmc & COUNTER_MAX) == COUNTER_MAX) BUG(); + (*bmc)++; + + spin_unlock_irq(&bitmap->lock); + + offset += blocks; + if (sectors > blocks) + sectors -= blocks; + else sectors = 0; + } + return 0; +} + +void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, + int success) +{ + if (!bitmap) return; + while (sectors) { + int blocks; + unsigned long flags; + bitmap_counter_t *bmc; + + spin_lock_irqsave(&bitmap->lock, flags); + bmc = bitmap_get_counter(bitmap, offset, &blocks, 0); + if (!bmc) { + spin_unlock_irqrestore(&bitmap->lock, flags); + return; + } + + if (!success && ! (*bmc & NEEDED_MASK)) + *bmc |= NEEDED_MASK; + + (*bmc)--; + if (*bmc <= 2) { + set_page_attr(bitmap, + filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)), + BITMAP_PAGE_CLEAN); + } + spin_unlock_irqrestore(&bitmap->lock, flags); + offset += blocks; + if (sectors > blocks) + sectors -= blocks; + else sectors = 0; + } +} + +int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks) +{ + bitmap_counter_t *bmc; + int rv; + if (bitmap == NULL) {/* FIXME or bitmap set as 'failed' */ + *blocks = 1024; + return 1; /* always resync if no bitmap */ + } + spin_lock_irq(&bitmap->lock); + bmc = bitmap_get_counter(bitmap, offset, blocks, 0); + rv = 0; + if (bmc) { + /* locked */ + if (RESYNC(*bmc)) + rv = 1; + else if (NEEDED(*bmc)) { + rv = 1; + *bmc |= RESYNC_MASK; + *bmc &= ~NEEDED_MASK; + } + } + spin_unlock_irq(&bitmap->lock); + return rv; +} + +void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted) +{ + bitmap_counter_t *bmc; + unsigned long flags; +/* + if (offset == 0) printk("bitmap_end_sync 0 (%d)\n", aborted); +*/ if (bitmap == NULL) { + *blocks = 1024; + return; + } + spin_lock_irqsave(&bitmap->lock, flags); + bmc = bitmap_get_counter(bitmap, offset, blocks, 0); + if (bmc == NULL) + goto unlock; + /* locked */ +/* + if (offset == 0) printk("bitmap_end sync found 0x%x, blocks %d\n", *bmc, *blocks); +*/ + if (RESYNC(*bmc)) { + *bmc &= ~RESYNC_MASK; + + if (!NEEDED(*bmc) && aborted) + *bmc |= NEEDED_MASK; + else { + if (*bmc <= 2) { + set_page_attr(bitmap, + filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)), + BITMAP_PAGE_CLEAN); + } + } + } + unlock: + spin_unlock_irqrestore(&bitmap->lock, flags); +} + +void bitmap_close_sync(struct bitmap *bitmap) +{ + /* Sync has finished, and any bitmap chunks that weren't synced + * properly have been aborted. It remains to us to clear the + * RESYNC bit wherever it is still on + */ + sector_t sector = 0; + int blocks; + if (!bitmap) return; + while (sector < bitmap->mddev->resync_max_sectors) { + bitmap_end_sync(bitmap, sector, &blocks, 0); +/* + if (sector < 500) printk("bitmap_close_sync: sec %llu blks %d\n", + (unsigned long long)sector, blocks); +*/ sector += blocks; + } +} + +static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, + unsigned long sectors, int set) +{ + /* For each chunk covered by any of these sectors, set the + * resync needed bit, and the counter to 1. They should all + * be 0 at this point + */ + while (sectors) { + int secs; + bitmap_counter_t *bmc; + spin_lock_irq(&bitmap->lock); + bmc = bitmap_get_counter(bitmap, offset, &secs, 1); + if (!bmc) { + spin_unlock_irq(&bitmap->lock); + return; + } + if (set && !NEEDED(*bmc)) { + BUG_ON(*bmc); + *bmc = NEEDED_MASK | 1; + bitmap_count_page(bitmap, offset, 1); + } + spin_unlock_irq(&bitmap->lock); + if (sectors > secs) + sectors -= secs; + else + sectors = 0; + } +} + +/* dirty the entire bitmap */ +int bitmap_setallbits(struct bitmap *bitmap) +{ + unsigned long flags; + unsigned long j; + + /* dirty the in-memory bitmap */ + bitmap_set_memory_bits(bitmap, 0, bitmap->chunks << CHUNK_BLOCK_SHIFT(bitmap), 1); + + /* dirty the bitmap file */ + for (j = 0; j < bitmap->file_pages; j++) { + struct page *page = bitmap->filemap[j]; + + spin_lock_irqsave(&bitmap->lock, flags); + page_cache_get(page); + spin_unlock_irqrestore(&bitmap->lock, flags); + memset(kmap(page), 0xff, PAGE_SIZE); + kunmap(page); + write_page(page, 0); + } + + return 0; +} + +/* + * free memory that was allocated + */ +void bitmap_destroy(mddev_t *mddev) +{ + unsigned long k, pages; + struct bitmap_page *bp; + struct bitmap *bitmap = mddev->bitmap; + + if (!bitmap) /* there was no bitmap */ + return; + + mddev->bitmap = NULL; /* disconnect from the md device */ + + /* release the bitmap file and kill the daemon */ + bitmap_file_put(bitmap); + + bp = bitmap->bp; + pages = bitmap->pages; + + /* free all allocated memory */ + + mempool_destroy(bitmap->write_pool); + + if (bp) /* deallocate the page memory */ + for (k = 0; k < pages; k++) + if (bp[k].map && !bp[k].hijacked) + kfree(bp[k].map); + kfree(bp); + kfree(bitmap); +} + +/* + * initialize the bitmap structure + * if this returns an error, bitmap_destroy must be called to do clean up + */ +int bitmap_create(mddev_t *mddev) +{ + struct bitmap *bitmap; + unsigned long blocks = mddev->resync_max_sectors; + unsigned long chunks; + unsigned long pages; + struct file *file = mddev->bitmap_file; + int err; + + BUG_ON(sizeof(bitmap_super_t) != 256); + + if (!file) /* bitmap disabled, nothing to do */ + return 0; + + bitmap = kmalloc(sizeof(*bitmap), GFP_KERNEL); + if (!bitmap) + return -ENOMEM; + + memset(bitmap, 0, sizeof(*bitmap)); + + spin_lock_init(&bitmap->lock); + bitmap->mddev = mddev; + mddev->bitmap = bitmap; + + spin_lock_init(&bitmap->write_lock); + init_MUTEX_LOCKED(&bitmap->write_done); + INIT_LIST_HEAD(&bitmap->complete_pages); + init_waitqueue_head(&bitmap->write_wait); + bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc, + write_pool_free, NULL); + if (!bitmap->write_pool) + return -ENOMEM; + + bitmap->file = file; + get_file(file); + /* read superblock from bitmap file (this sets bitmap->chunksize) */ + err = bitmap_read_sb(bitmap); + if (err) + return err; + + bitmap->chunkshift = find_first_bit(&bitmap->chunksize, + sizeof(bitmap->chunksize)); + + /* now that chunksize and chunkshift are set, we can use these macros */ + chunks = (blocks + CHUNK_BLOCK_RATIO(bitmap) - 1) / + CHUNK_BLOCK_RATIO(bitmap); + pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO; + + BUG_ON(!pages); + + bitmap->chunks = chunks; + bitmap->pages = pages; + bitmap->missing_pages = pages; + bitmap->counter_bits = COUNTER_BITS; + + bitmap->syncchunk = ~0UL; + +#if INJECT_FATAL_FAULT_1 + bitmap->bp = NULL; +#else + bitmap->bp = kmalloc(pages * sizeof(*bitmap->bp), GFP_KERNEL); +#endif + if (!bitmap->bp) + return -ENOMEM; + memset(bitmap->bp, 0, pages * sizeof(*bitmap->bp)); + + bitmap->flags |= BITMAP_ACTIVE; + + /* now that we have some pages available, initialize the in-memory + * bitmap from the on-disk bitmap */ + err = bitmap_init_from_disk(bitmap); + if (err) + return err; + + printk(KERN_INFO "created bitmap (%lu pages) for device %s\n", + pages, bmname(bitmap)); + + /* kick off the bitmap daemons */ + err = bitmap_start_daemons(bitmap); + if (err) + return err; + return bitmap_update_sb(bitmap); +} + +/* the bitmap API -- for raid personalities */ +EXPORT_SYMBOL(bitmap_startwrite); +EXPORT_SYMBOL(bitmap_endwrite); +EXPORT_SYMBOL(bitmap_start_sync); +EXPORT_SYMBOL(bitmap_end_sync); +EXPORT_SYMBOL(bitmap_unplug); +EXPORT_SYMBOL(bitmap_close_sync); +EXPORT_SYMBOL(bitmap_daemon_work); diff --git a/drivers/md/md.c b/drivers/md/md.c index fa608a1..c402f6c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -19,6 +19,9 @@ Neil Brown . + - persistent bitmap code + Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc. + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) @@ -33,6 +36,7 @@ #include #include #include +#include #include #include #include /* for invalidate_bdev */ @@ -40,6 +44,8 @@ #include +#include + #ifdef CONFIG_KMOD #include #endif @@ -1198,8 +1204,11 @@ void md_print_devices(void) printk("md: * *\n"); printk("md: **********************************\n"); ITERATE_MDDEV(mddev,tmp) { - printk("%s: ", mdname(mddev)); + if (mddev->bitmap) + bitmap_print_sb(mddev->bitmap); + else + printk("%s: ", mdname(mddev)); ITERATE_RDEV(mddev,rdev,tmp2) printk("<%s>", bdevname(rdev->bdev,b)); printk("\n"); @@ -1287,7 +1296,7 @@ repeat: "md: updating %s RAID superblock on device (in sync %d)\n", mdname(mddev),mddev->in_sync); - err = 0; + err = bitmap_update_sb(mddev->bitmap); ITERATE_RDEV(mddev,rdev,tmp) { char b[BDEVNAME_SIZE]; dprintk(KERN_INFO "md: "); @@ -1624,12 +1633,19 @@ static int do_md_run(mddev_t * mddev) mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ - err = mddev->pers->run(mddev); + /* before we start the array running, initialise the bitmap */ + err = bitmap_create(mddev); + if (err) + printk(KERN_ERR "%s: failed to create bitmap (%d)\n", + mdname(mddev), err); + else + err = mddev->pers->run(mddev); if (err) { printk(KERN_ERR "md: pers->run() failed ...\n"); module_put(mddev->pers->owner); mddev->pers = NULL; - return -EINVAL; + bitmap_destroy(mddev); + return err; } atomic_set(&mddev->writes_pending,0); mddev->safemode = 0; @@ -1742,6 +1758,14 @@ static int do_md_stop(mddev_t * mddev, int ro) if (ro) set_disk_ro(disk, 1); } + + bitmap_destroy(mddev); + if (mddev->bitmap_file) { + atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1); + fput(mddev->bitmap_file); + mddev->bitmap_file = NULL; + } + /* * Free resources if final stop */ @@ -2000,6 +2024,42 @@ static int get_array_info(mddev_t * mddev, void __user * arg) return 0; } +static int get_bitmap_file(mddev_t * mddev, void * arg) +{ + mdu_bitmap_file_t *file = NULL; /* too big for stack allocation */ + char *ptr, *buf = NULL; + int err = -ENOMEM; + + file = kmalloc(sizeof(*file), GFP_KERNEL); + if (!file) + goto out; + + /* bitmap disabled, zero the first byte and copy out */ + if (!mddev->bitmap || !mddev->bitmap->file) { + file->pathname[0] = '\0'; + goto copy_out; + } + + buf = kmalloc(sizeof(file->pathname), GFP_KERNEL); + if (!buf) + goto out; + + ptr = file_path(mddev->bitmap->file, buf, sizeof(file->pathname)); + if (!ptr) + goto out; + + strcpy(file->pathname, ptr); + +copy_out: + err = 0; + if (copy_to_user(arg, file, sizeof(*file))) + err = -EFAULT; +out: + kfree(buf); + kfree(file); + return err; +} + static int get_disk_info(mddev_t * mddev, void __user * arg) { mdu_disk_info_t info; @@ -2275,6 +2335,48 @@ abort_export: return err; } +/* similar to deny_write_access, but accounts for our holding a reference + * to the file ourselves */ +static int deny_bitmap_write_access(struct file * file) +{ + struct inode *inode = file->f_mapping->host; + + spin_lock(&inode->i_lock); + if (atomic_read(&inode->i_writecount) > 1) { + spin_unlock(&inode->i_lock); + return -ETXTBSY; + } + atomic_set(&inode->i_writecount, -1); + spin_unlock(&inode->i_lock); + + return 0; +} + +static int set_bitmap_file(mddev_t *mddev, int fd) +{ + int err; + + if (mddev->pers) + return -EBUSY; + + mddev->bitmap_file = fget(fd); + + if (mddev->bitmap_file == NULL) { + printk(KERN_ERR "%s: error: failed to get bitmap file\n", + mdname(mddev)); + return -EBADF; + } + + err = deny_bitmap_write_access(mddev->bitmap_file); + if (err) { + printk(KERN_ERR "%s: error: bitmap file is already in use\n", + mdname(mddev)); + fput(mddev->bitmap_file); + mddev->bitmap_file = NULL; + } + return err; +} + /* * set_array_info is used two different ways * The original usage is when creating a new array. @@ -2586,8 +2688,10 @@ static int md_ioctl(struct inode *inode, struct file *file, /* * Commands querying/configuring an existing array: */ - /* if we are initialised yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */ - if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY && cmd != RUN_ARRAY) { + /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY, + * RUN_ARRAY, and SET_BITMAP_FILE are allowed */ + if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY + && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE) { err = -ENODEV; goto abort_unlock; } @@ -2601,6 +2705,10 @@ static int md_ioctl(struct inode *inode, struct file *file, err = get_array_info(mddev, argp); goto done_unlock; + case GET_BITMAP_FILE: + err = get_bitmap_file(mddev, (void *)arg); + goto done_unlock; + case GET_DISK_INFO: err = get_disk_info(mddev, argp); goto done_unlock; @@ -2681,6 +2789,10 @@ static int md_ioctl(struct inode *inode, struct file *file, err = do_md_run (mddev); goto done_unlock; + case SET_BITMAP_FILE: + err = set_bitmap_file(mddev, (int)arg); + goto done_unlock; + default: if (_IOC_TYPE(cmd) == MD_MAJOR) printk(KERN_WARNING "md: %s(pid %d) used" @@ -2792,8 +2904,9 @@ static int md_thread(void * arg) while (thread->run) { void (*run)(mddev_t *); - wait_event_interruptible(thread->wqueue, - test_bit(THREAD_WAKEUP, &thread->flags)); + wait_event_interruptible_timeout(thread->wqueue, + test_bit(THREAD_WAKEUP, &thread->flags), + thread->timeout); if (current->flags & PF_FREEZE) refrigerator(PF_FREEZE); @@ -2839,6 +2952,7 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev, thread->run = run; thread->mddev = mddev; thread->name = name; + thread->timeout = MAX_SCHEDULE_TIMEOUT; ret = kernel_thread(md_thread, thread, 0); if (ret < 0) { kfree(thread); @@ -2877,13 +2991,13 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev) if (!rdev || rdev->faulty) return; - +/* dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n", mdname(mddev), MAJOR(rdev->bdev->bd_dev), MINOR(rdev->bdev->bd_dev), __builtin_return_address(0),__builtin_return_address(1), __builtin_return_address(2),__builtin_return_address(3)); - +*/ if (!mddev->pers->error_handler) return; mddev->pers->error_handler(mddev,rdev); @@ -3037,6 +3151,7 @@ static int md_seq_show(struct seq_file *seq, void *v) struct list_head *tmp2; mdk_rdev_t *rdev; int i; + struct bitmap *bitmap; if (v == (void*)1) { seq_printf(seq, "Personalities : "); @@ -3089,10 +3204,36 @@ static int md_seq_show(struct seq_file *seq, void *v) if (mddev->pers) { mddev->pers->status (seq, mddev); seq_printf(seq, "\n "); - if (mddev->curr_resync > 2) + if (mddev->curr_resync > 2) { status_resync (seq, mddev); - else if (mddev->curr_resync == 1 || mddev->curr_resync == 2) - seq_printf(seq, " resync=DELAYED"); + seq_printf(seq, "\n "); + } else if (mddev->curr_resync == 1 || mddev->curr_resync == 2) + seq_printf(seq, " resync=DELAYED\n "); + } else + seq_printf(seq, "\n "); + + if ((bitmap = mddev->bitmap)) { + char *buf, *path; + unsigned long chunk_kb; + unsigned long flags; + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + spin_lock_irqsave(&bitmap->lock, flags); + chunk_kb = bitmap->chunksize >> 10; + seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], " + "%lu%s chunk", + bitmap->pages - bitmap->missing_pages, + bitmap->pages, + (bitmap->pages - bitmap->missing_pages) + << (PAGE_SHIFT - 10), + chunk_kb ? chunk_kb : bitmap->chunksize, + chunk_kb ? "KB" : "B"); + if (bitmap->file && buf) { + path = file_path(bitmap->file, buf, PAGE_SIZE); + seq_printf(seq, ", file: %s", path ? path : ""); + } + seq_printf(seq, "\n"); + spin_unlock_irqrestore(&bitmap->lock, flags); + kfree(buf); } seq_printf(seq, "\n"); @@ -3328,7 +3469,8 @@ static void md_do_sync(mddev_t *mddev) sysctl_speed_limit_max); is_mddev_idle(mddev); /* this also initializes IO event counters */ - if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) + /* we don't use the checkpoint if there's a bitmap */ + if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !mddev->bitmap) j = mddev->recovery_cp; else j = 0; @@ -3673,6 +3815,8 @@ static int __init md_init(void) " MD_SB_DISKS=%d\n", MD_MAJOR_VERSION, MD_MINOR_VERSION, MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS); + printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR, + BITMAP_MINOR); if (register_blkdev(MAJOR_NR, "md")) return -1; diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h new file mode 100644 index 0000000..f785cf2 --- /dev/null +++ b/include/linux/raid/bitmap.h @@ -0,0 +1,280 @@ +/* + * bitmap.h: Copyright (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003 + * + * additions: Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc. + */ +#ifndef BITMAP_H +#define BITMAP_H 1 + +#define BITMAP_MAJOR 3 +#define BITMAP_MINOR 38 + +/* + * in-memory bitmap: + * + * Use 16 bit block counters to track pending writes to each "chunk". + * The 2 high order bits are special-purpose, the first is a flag indicating + * whether a resync is needed. The second is a flag indicating whether a + * resync is active. + * This means that the counter is actually 14 bits: + * + * +--------+--------+------------------------------------------------+ + * | resync | resync | counter | + * | needed | active | | + * | (0-1) | (0-1) | (0-16383) | + * +--------+--------+------------------------------------------------+ + * + * The "resync needed" bit is set when: + * a '1' bit is read from storage at startup. + * a write request fails on some drives + * a resync is aborted on a chunk with 'resync active' set + * It is cleared (and resync-active set) when a resync starts across all drives + * of the chunk. + * + * + * The "resync active" bit is set when: + * a resync is started on all drives, and resync_needed is set. + * resync_needed will be cleared (as long as resync_active wasn't already set). + * It is cleared when a resync completes. + * + * The counter counts pending write requests, plus the on-disk bit. + * When the counter is '1' and the resync bits are clear, the on-disk + * bit can be cleared aswell, thus setting the counter to 0. + * When we set a bit, or in the counter (to start a write), if the fields is + * 0, we first set the disk bit and set the counter to 1. + * + * If the counter is 0, the on-disk bit is clear and the stipe is clean + * Anything that dirties the stipe pushes the counter to 2 (at least) + * and sets the on-disk bit (lazily). + * If a periodic sweep find the counter at 2, it is decremented to 1. + * If the sweep find the counter at 1, the on-disk bit is cleared and the + * counter goes to zero. + * + * Also, we'll hijack the "map" pointer itself and use it as two 16 bit block + * counters as a fallback when "page" memory cannot be allocated: + * + * Normal case (page memory allocated): + * + * page pointer (32-bit) + * + * [ ] ------+ + * | + * +-------> [ ][ ]..[ ] (4096 byte page == 2048 counters) + * c1 c2 c2048 + * + * Hijacked case (page memory allocation failed): + * + * hijacked page pointer (32-bit) + * + * [ ][ ] (no page memory allocated) + * counter #1 (16-bit) counter #2 (16-bit) + * + */ + +#ifdef __KERNEL__ + +#define PAGE_BITS (PAGE_SIZE << 3) +#define PAGE_BIT_SHIFT (PAGE_SHIFT + 3) + +typedef __u16 bitmap_counter_t; +#define COUNTER_BITS 16 +#define COUNTER_BIT_SHIFT 4 +#define COUNTER_BYTE_RATIO (COUNTER_BITS / 8) +#define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3) + +#define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1))) +#define RESYNC_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 2))) +#define COUNTER_MAX ((bitmap_counter_t) RESYNC_MASK - 1) +#define NEEDED(x) (((bitmap_counter_t) x) & NEEDED_MASK) +#define RESYNC(x) (((bitmap_counter_t) x) & RESYNC_MASK) +#define COUNTER(x) (((bitmap_counter_t) x) & COUNTER_MAX) + +/* how many counters per page? */ +#define PAGE_COUNTER_RATIO (PAGE_BITS / COUNTER_BITS) +/* same, except a shift value for more efficient bitops */ +#define PAGE_COUNTER_SHIFT (PAGE_BIT_SHIFT - COUNTER_BIT_SHIFT) +/* same, except a mask value for more efficient bitops */ +#define PAGE_COUNTER_MASK (PAGE_COUNTER_RATIO - 1) + +#define BITMAP_BLOCK_SIZE 512 +#define BITMAP_BLOCK_SHIFT 9 + +/* how many blocks per chunk? (this is variable) */ +#define CHUNK_BLOCK_RATIO(bitmap) ((bitmap)->chunksize >> BITMAP_BLOCK_SHIFT) +#define CHUNK_BLOCK_SHIFT(bitmap) ((bitmap)->chunkshift - BITMAP_BLOCK_SHIFT) +#define CHUNK_BLOCK_MASK(bitmap) (CHUNK_BLOCK_RATIO(bitmap) - 1) + +/* when hijacked, the counters and bits represent even larger "chunks" */ +/* there will be 1024 chunks represented by each counter in the page pointers */ +#define PAGEPTR_BLOCK_RATIO(bitmap) \ + (CHUNK_BLOCK_RATIO(bitmap) << PAGE_COUNTER_SHIFT >> 1) +#define PAGEPTR_BLOCK_SHIFT(bitmap) \ + (CHUNK_BLOCK_SHIFT(bitmap) + PAGE_COUNTER_SHIFT - 1) +#define PAGEPTR_BLOCK_MASK(bitmap) (PAGEPTR_BLOCK_RATIO(bitmap) - 1) + +/* + * on-disk bitmap: + * + * Use one bit per "chunk" (block set). We do the disk I/O on the bitmap + * file a page at a time. There's a superblock at the start of the file. + */ + +/* map chunks (bits) to file pages - offset by the size of the superblock */ +#define CHUNK_BIT_OFFSET(chunk) ((chunk) + (sizeof(bitmap_super_t) << 3)) + +#endif + +/* + * bitmap structures: + */ + +#define BITMAP_MAGIC 0x6d746962 + +/* use these for bitmap->flags and bitmap->sb->state bit-fields */ +enum bitmap_state { + BITMAP_ACTIVE = 0x001, /* the bitmap is in use */ + BITMAP_STALE = 0x002 /* the bitmap file is out of date or had -EIO */ +}; + +/* the superblock at the front of the bitmap file -- little endian */ +typedef struct bitmap_super_s { + __u32 magic; /* 0 BITMAP_MAGIC */ + __u32 version; /* 4 the bitmap major for now, could change... */ + __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */ + __u64 events; /* 24 event counter for the bitmap (1)*/ + __u64 events_cleared;/*32 event counter when last bit cleared (2) */ + __u64 sync_size; /* 40 the size of the md device's sync range(3) */ + __u32 state; /* 48 bitmap state information */ + __u32 chunksize; /* 52 the bitmap chunk size in bytes */ + __u32 daemon_sleep; /* 56 seconds between disk flushes */ + + __u8 pad[256 - 60]; /* set to zero */ +} bitmap_super_t; + +/* notes: + * (1) This event counter is updated before the eventcounter in the md superblock + * When a bitmap is loaded, it is only accepted if this event counter is equal + * to, or one greater than, the event counter in the superblock. + * (2) This event counter is updated when the other one is *if*and*only*if* the + * array is not degraded. As bits are not cleared when the array is degraded, + * this represents the last time that any bits were cleared. + * If a device is being added that has an event count with this value or + * higher, it is accepted as conforming to the bitmap. + * (3)This is the number of sectors represented by the bitmap, and is the range that + * resync happens across. For raid1 and raid5/6 it is the size of individual + * devices. For raid10 it is the size of the array. + */ + +#ifdef __KERNEL__ + +/* the in-memory bitmap is represented by bitmap_pages */ +struct bitmap_page { + /* + * map points to the actual memory page + */ + char *map; + /* + * in emergencies (when map cannot be alloced), hijack the map + * pointer and use it as two counters itself + */ + unsigned int hijacked:1; + /* + * count of dirty bits on the page + */ + unsigned int count:31; +}; + +/* keep track of bitmap file pages that have pending writes on them */ +struct page_list { + struct list_head list; + struct page *page; +}; + +/* the main bitmap structure - one per mddev */ +struct bitmap { + struct bitmap_page *bp; + unsigned long pages; /* total number of pages in the bitmap */ + unsigned long missing_pages; /* number of pages not yet allocated */ + + mddev_t *mddev; /* the md device that the bitmap is for */ + + int counter_bits; /* how many bits per block counter */ + + /* bitmap chunksize -- how much data does each bit represent? */ + unsigned long chunksize; + unsigned long chunkshift; /* chunksize = 2^chunkshift (for bitops) */ + unsigned long chunks; /* total number of data chunks for the array */ + + /* We hold a count on the chunk currently being synced, and drop + * it when the last block is started. If the resync is aborted + * midway, we need to be able to drop that count, so we remember + * the counted chunk.. + */ + unsigned long syncchunk; + + __u64 events_cleared; + + /* bitmap spinlock */ + spinlock_t lock; + + struct file *file; /* backing disk file */ + struct page *sb_page; /* cached copy of the bitmap file superblock */ + struct page **filemap; /* list of cache pages for the file */ + unsigned long *filemap_attr; /* attributes associated w/ filemap pages */ + unsigned long file_pages; /* number of pages in the file */ + + unsigned long flags; + + /* + * the bitmap daemon - periodically wakes up and sweeps the bitmap + * file, cleaning up bits and flushing out pages to disk as necessary + */ + unsigned long daemon_lastrun; /* jiffies of last run */ + unsigned long daemon_sleep; /* how many seconds between updates? */ + + /* + * bitmap write daemon - this daemon performs writes to the bitmap file + * this thread is only needed because of a limitation in ext3 (jbd) + * that does not allow a task to have two journal transactions ongoing + * simultaneously (even if the transactions are for two different + * filesystems) -- in the case of bitmap, that would be the filesystem + * that the bitmap file resides on and the filesystem that is mounted + * on the md device -- see current->journal_info in jbd/transaction.c + */ + mdk_thread_t *writeback_daemon; + spinlock_t write_lock; + struct semaphore write_ready; + struct semaphore write_done; + unsigned long writes_pending; + wait_queue_head_t write_wait; + struct list_head write_pages; + struct list_head complete_pages; + mempool_t *write_pool; +}; + +/* the bitmap API */ + +/* these are used only by md/bitmap */ +int bitmap_create(mddev_t *mddev); +void bitmap_destroy(mddev_t *mddev); +int bitmap_active(struct bitmap *bitmap); + +char *file_path(struct file *file, char *buf, int count); +void bitmap_print_sb(struct bitmap *bitmap); +int bitmap_update_sb(struct bitmap *bitmap); + +int bitmap_setallbits(struct bitmap *bitmap); + +/* these are exported */ +int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors); +void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, + int success); +int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks); +void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted); +void bitmap_close_sync(struct bitmap *bitmap); + +int bitmap_unplug(struct bitmap *bitmap); +int bitmap_daemon_work(struct bitmap *bitmap); +#endif + +#endif diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index bce0032..16e94a9 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -267,6 +267,9 @@ struct mddev_s atomic_t writes_pending; request_queue_t *queue; /* for plugging ... */ + struct bitmap *bitmap; /* the bitmap for the device */ + struct file *bitmap_file; /* the bitmap file */ + struct list_head all_mddevs; }; @@ -341,6 +344,7 @@ typedef struct mdk_thread_s { unsigned long flags; struct completion *event; struct task_struct *tsk; + unsigned long timeout; const char *name; } mdk_thread_t; diff --git a/include/linux/raid/md_u.h b/include/linux/raid/md_u.h index a2df5c2..81da20c 100644 --- a/include/linux/raid/md_u.h +++ b/include/linux/raid/md_u.h @@ -23,6 +23,7 @@ #define GET_DISK_INFO _IOR (MD_MAJOR, 0x12, mdu_disk_info_t) #define PRINT_RAID_DEBUG _IO (MD_MAJOR, 0x13) #define RAID_AUTORUN _IO (MD_MAJOR, 0x14) +#define GET_BITMAP_FILE _IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t) /* configuration */ #define CLEAR_ARRAY _IO (MD_MAJOR, 0x20) @@ -36,6 +37,7 @@ #define HOT_ADD_DISK _IO (MD_MAJOR, 0x28) #define SET_DISK_FAULTY _IO (MD_MAJOR, 0x29) #define HOT_GENERATE_ERROR _IO (MD_MAJOR, 0x2a) +#define SET_BITMAP_FILE _IOW (MD_MAJOR, 0x2b, int) /* usage */ #define RUN_ARRAY _IOW (MD_MAJOR, 0x30, mdu_param_t) @@ -106,6 +108,11 @@ typedef struct mdu_start_info_s { } mdu_start_info_t; +typedef struct mdu_bitmap_file_s +{ + char pathname[4096]; +} mdu_bitmap_file_t; + typedef struct mdu_param_s { int personality; /* 1,2,3,4 */ -- cgit v0.10.2 From 78d742d876bdf7263d0d966fbe9593559fd904a7 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:15 -0700 Subject: [PATCH] md: a couple of tidyups relating to the bitmap file. 1/ When init from disk, it is a BUG if there is nowhere to init from, 2/ use seq_path to print path in /proc/mdstat Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 34ffc13..b43bdb2 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -769,13 +769,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) chunks = bitmap->chunks; file = bitmap->file; - if (!file) { /* no file, dirty all the in-memory bits */ - printk(KERN_INFO "%s: no bitmap file, doing full recovery\n", - bmname(bitmap)); - bitmap_set_memory_bits(bitmap, 0, - chunks << CHUNK_BLOCK_SHIFT(bitmap), 1); - return 0; - } + BUG_ON(!file); #if INJECT_FAULTS_3 outofdate = 1; diff --git a/drivers/md/md.c b/drivers/md/md.c index c402f6c..52fafb8 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3213,10 +3213,8 @@ static int md_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "\n "); if ((bitmap = mddev->bitmap)) { - char *buf, *path; unsigned long chunk_kb; unsigned long flags; - buf = kmalloc(PAGE_SIZE, GFP_KERNEL); spin_lock_irqsave(&bitmap->lock, flags); chunk_kb = bitmap->chunksize >> 10; seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], " @@ -3227,13 +3225,14 @@ static int md_seq_show(struct seq_file *seq, void *v) << (PAGE_SHIFT - 10), chunk_kb ? chunk_kb : bitmap->chunksize, chunk_kb ? "KB" : "B"); - if (bitmap->file && buf) { - path = file_path(bitmap->file, buf, PAGE_SIZE); - seq_printf(seq, ", file: %s", path ? path : ""); + if (bitmap->file) { + seq_printf(seq, ", file: "); + seq_path(seq, bitmap->file->f_vfsmnt, + bitmap->file->f_dentry," \t\n"); } + seq_printf(seq, "\n"); spin_unlock_irqrestore(&bitmap->lock, flags); - kfree(buf); } seq_printf(seq, "\n"); -- cgit v0.10.2 From 5f40402d96cb21df912e5bbb3fffa5e1afc81e98 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:16 -0700 Subject: [PATCH] md: call bitmap_daemon_work regularly bitmap_daemon_work clears bits in the bitmap for blocks that haven't been written to for a while. It needs to be called regularly to make sure the bitmap doesn't endup full of ones .... but it wasn't. So call it from the increasingly-inaptly-named md_check_recovery Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/md.c b/drivers/md/md.c index 52fafb8..b02f8d1 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3635,7 +3635,8 @@ void md_check_recovery(mddev_t *mddev) struct list_head *rtmp; - dprintk(KERN_INFO "md: recovery thread got woken up ...\n"); + if (mddev->bitmap) + bitmap_daemon_work(mddev->bitmap); if (mddev->ro) return; -- cgit v0.10.2 From d80a138c013f81c1b9383c83983934e34e380a2d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:17 -0700 Subject: [PATCH] md: print correct pid for newly created bitmap-writeback-daemon. The debugging message printed the wrong pid, which didn't help remove bugs.... Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index b43bdb2..c43fd03 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1112,7 +1112,7 @@ static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr, md_wakeup_thread(daemon); /* start it running */ PRINTK("%s: %s daemon (pid %d) started...\n", - bmname(bitmap), name, bitmap->daemon->tsk->pid); + bmname(bitmap), name, daemon->tsk->pid); out_unlock: spin_unlock_irqrestore(&bitmap->lock, flags); return 0; -- cgit v0.10.2 From bc7f77de2cd81718dd789a2cfe68a7cf1b48f016 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:17 -0700 Subject: [PATCH] md: minor code rearrangement in bitmap_init_from_disk Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index c43fd03..62fac2b 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -781,7 +781,9 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) "recovery\n", bmname(bitmap)); bytes = (chunks + 7) / 8; - num_pages = (bytes + PAGE_SIZE - 1) / PAGE_SIZE; + + num_pages = (bytes + sizeof(bitmap_super_t) + PAGE_SIZE - 1) / PAGE_SIZE + 1; + if (i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) { printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n", bmname(bitmap), @@ -789,18 +791,16 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) bytes + sizeof(bitmap_super_t)); goto out; } - num_pages++; + + ret = -ENOMEM; + bitmap->filemap = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL); - if (!bitmap->filemap) { - ret = -ENOMEM; + if (!bitmap->filemap) goto out; - } bitmap->filemap_attr = kmalloc(sizeof(long) * num_pages, GFP_KERNEL); - if (!bitmap->filemap_attr) { - ret = -ENOMEM; + if (!bitmap->filemap_attr) goto out; - } memset(bitmap->filemap_attr, 0, sizeof(long) * num_pages); -- cgit v0.10.2 From cdbb4cc2e5c30895709163d8544057db21ee23e0 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:18 -0700 Subject: [PATCH] md: make sure md bitmap is cleared on a clean start. As the array-wide clean bit (in the superblock) is set more agressively than the bits in the bitmap are cleared, it is possible to have an array which is clean despite there being bits set in the bitmap. These bits will currently never get cleared, as they can only be cleared by a resync pass, which never happens. No, when reading bits from disk, be aware of whether the whole array is known to be in sync, and act accordingly. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 62fac2b..275a2aa 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -747,7 +747,7 @@ int bitmap_unplug(struct bitmap *bitmap) } static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, - unsigned long sectors, int set); + unsigned long sectors, int in_sync); /* * bitmap_init_from_disk -- called at bitmap_create time to initialize * the in-memory bitmap from the on-disk bitmap -- also, sets up the * memory mapping of the bitmap file @@ -756,7 +756,7 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, * previously kicked from the array, we mark all the bits as * 1's in order to cause a full resync. */ -static int bitmap_init_from_disk(struct bitmap *bitmap) +static int bitmap_init_from_disk(struct bitmap *bitmap, int in_sync) { unsigned long i, chunks, index, oldindex, bit; struct page *page = NULL, *oldpage = NULL; @@ -782,7 +782,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) bytes = (chunks + 7) / 8; - num_pages = (bytes + sizeof(bitmap_super_t) + PAGE_SIZE - 1) / PAGE_SIZE + 1; + num_pages = (bytes + sizeof(bitmap_super_t) + PAGE_SIZE - 1) / PAGE_SIZE; if (i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) { printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n", @@ -854,14 +854,9 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) if (test_bit(bit, page_address(page))) { /* if the disk bit is set, set the memory bit */ bitmap_set_memory_bits(bitmap, - i << CHUNK_BLOCK_SHIFT(bitmap), 1, 1); + i << CHUNK_BLOCK_SHIFT(bitmap), 1, in_sync); bit_cnt++; } -#if 0 - else - bitmap_set_memory_bits(bitmap, - i << CHUNK_BLOCK_SHIFT(bitmap), 1, 0); -#endif } /* everything went OK */ @@ -1331,10 +1326,10 @@ void bitmap_close_sync(struct bitmap *bitmap) } static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, - unsigned long sectors, int set) + unsigned long sectors, int in_sync) { /* For each chunk covered by any of these sectors, set the - * resync needed bit, and the counter to 1. They should all + * counter to 1 and set resync_needed unless in_sync. They should all * be 0 at this point */ while (sectors) { @@ -1346,10 +1341,12 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, spin_unlock_irq(&bitmap->lock); return; } - if (set && !NEEDED(*bmc)) { - BUG_ON(*bmc); - *bmc = NEEDED_MASK | 1; + if (! *bmc) { + struct page *page; + *bmc = 1 | (in_sync? 0 : NEEDED_MASK); bitmap_count_page(bitmap, offset, 1); + page = filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)); + set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); } spin_unlock_irq(&bitmap->lock); if (sectors > secs) @@ -1489,7 +1486,7 @@ int bitmap_create(mddev_t *mddev) /* now that we have some pages available, initialize the in-memory * bitmap from the on-disk bitmap */ - err = bitmap_init_from_disk(bitmap); + err = bitmap_init_from_disk(bitmap, mddev->recovery_cp == MaxSector); if (err) return err; -- cgit v0.10.2 From fc7ca163a448dfb23f44c9a47ebc8cbe52cf49df Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Tue, 21 Jun 2005 17:17:19 -0700 Subject: [PATCH] md printk fix A u64 is not an unsigned long long. On power4 it is `long', and printk warns. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 275a2aa..dd84e15 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -377,7 +377,8 @@ void bitmap_print_sb(struct bitmap *bitmap) printk(KERN_DEBUG " state: %08x\n", le32_to_cpu(sb->state)); printk(KERN_DEBUG " chunksize: %d B\n", le32_to_cpu(sb->chunksize)); printk(KERN_DEBUG "daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep)); - printk(KERN_DEBUG " sync size: %llu KB\n", le64_to_cpu(sb->sync_size)); + printk(KERN_DEBUG " sync size: %llu KB\n", + (unsigned long long)le64_to_cpu(sb->sync_size)); kunmap(bitmap->sb_page); } -- cgit v0.10.2 From a2cff26ad18a8794722fb0d3c019d93e14fce3f1 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:20 -0700 Subject: [PATCH] md: improve debug-printing of bitmap superblock. - report sync_size properly - need /2 to convert sectors to KB - move everything over 2 spaces to allow proper spelling of "events cleared". Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index dd84e15..f197db2 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -363,22 +363,22 @@ void bitmap_print_sb(struct bitmap *bitmap) return; sb = (bitmap_super_t *)kmap(bitmap->sb_page); printk(KERN_DEBUG "%s: bitmap file superblock:\n", bmname(bitmap)); - printk(KERN_DEBUG " magic: %08x\n", le32_to_cpu(sb->magic)); - printk(KERN_DEBUG " version: %d\n", le32_to_cpu(sb->version)); - printk(KERN_DEBUG " uuid: %08x.%08x.%08x.%08x\n", + printk(KERN_DEBUG " magic: %08x\n", le32_to_cpu(sb->magic)); + printk(KERN_DEBUG " version: %d\n", le32_to_cpu(sb->version)); + printk(KERN_DEBUG " uuid: %08x.%08x.%08x.%08x\n", *(__u32 *)(sb->uuid+0), *(__u32 *)(sb->uuid+4), *(__u32 *)(sb->uuid+8), *(__u32 *)(sb->uuid+12)); - printk(KERN_DEBUG " events: %llu\n", + printk(KERN_DEBUG " events: %llu\n", (unsigned long long) le64_to_cpu(sb->events)); - printk(KERN_DEBUG "events_clred: %llu\n", + printk(KERN_DEBUG "events cleared: %llu\n", (unsigned long long) le64_to_cpu(sb->events_cleared)); - printk(KERN_DEBUG " state: %08x\n", le32_to_cpu(sb->state)); - printk(KERN_DEBUG " chunksize: %d B\n", le32_to_cpu(sb->chunksize)); - printk(KERN_DEBUG "daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep)); - printk(KERN_DEBUG " sync size: %llu KB\n", - (unsigned long long)le64_to_cpu(sb->sync_size)); + printk(KERN_DEBUG " state: %08x\n", le32_to_cpu(sb->state)); + printk(KERN_DEBUG " chunksize: %d B\n", le32_to_cpu(sb->chunksize)); + printk(KERN_DEBUG " daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep)); + printk(KERN_DEBUG " sync size: %llu KB\n", + (unsigned long long)le64_to_cpu(sb->sync_size)/2); kunmap(bitmap->sb_page); } -- cgit v0.10.2 From bfb39fba4e8cdda091f9ebee29fbb8331c4bb605 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:20 -0700 Subject: [PATCH] md: check return value of write_page, rather than ignore it Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index f197db2..9462fdd 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -350,8 +350,7 @@ int bitmap_update_sb(struct bitmap *bitmap) if (!bitmap->mddev->degraded) sb->events_cleared = cpu_to_le64(bitmap->mddev->events); kunmap(bitmap->sb_page); - write_page(bitmap->sb_page, 0); - return 0; + return write_page(bitmap->sb_page, 0); } /* print out the bitmap file superblock */ @@ -735,7 +734,8 @@ int bitmap_unplug(struct bitmap *bitmap) spin_unlock_irqrestore(&bitmap->lock, flags); if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) - write_page(page, 0); + if (write_page(page, 0)) + return 1; } if (wait) { /* if any writes were performed, we need to wait on them */ spin_lock_irq(&bitmap->write_lock); @@ -950,7 +950,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) { clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); - write_page(lastpage, 0); + err = write_page(lastpage, 0); } else { set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); @@ -998,7 +998,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) { clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); - write_page(lastpage, 0); + err = write_page(lastpage, 0); } else { set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); @@ -1375,7 +1375,8 @@ int bitmap_setallbits(struct bitmap *bitmap) spin_unlock_irqrestore(&bitmap->lock, flags); memset(kmap(page), 0xff, PAGE_SIZE); kunmap(page); - write_page(page, 0); + if (write_page(page, 0)) + return 1; } return 0; -- cgit v0.10.2 From 77ad4bc706fe6c52ab953f31c287a6af712d080c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:21 -0700 Subject: [PATCH] md: enable the bitmap write-back daemon and wait for it. Currently we don't wait for updates to the bitmap to be flushed to disk properly. The infrastructure all there, but it isn't being used.... A separate kernel thread (bitmap_writeback_daemon) is needed to wait for each page as we cannot get callbacks when a page write completes. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 9462fdd..86b6b03 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -261,30 +261,33 @@ char *file_path(struct file *file, char *buf, int count) /* * write out a page */ -static int write_page(struct page *page, int wait) +static int write_page(struct bitmap *bitmap, struct page *page, int wait) { int ret = -ENOMEM; lock_page(page); - if (page->mapping == NULL) - goto unlock_out; - else if (i_size_read(page->mapping->host) < page->index << PAGE_SHIFT) { - ret = -ENOENT; - goto unlock_out; - } - ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE); if (!ret) ret = page->mapping->a_ops->commit_write(NULL, page, 0, PAGE_SIZE); if (ret) { -unlock_out: unlock_page(page); return ret; } set_page_dirty(page); /* force it to be written out */ + + if (!wait) { + /* add to list to be waited for by daemon */ + struct page_list *item = mempool_alloc(bitmap->write_pool, GFP_NOIO); + item->page = page; + page_cache_get(page); + spin_lock(&bitmap->write_lock); + list_add(&item->list, &bitmap->complete_pages); + spin_unlock(&bitmap->write_lock); + md_wakeup_thread(bitmap->writeback_daemon); + } return write_one_page(page, wait); } @@ -343,14 +346,13 @@ int bitmap_update_sb(struct bitmap *bitmap) spin_unlock_irqrestore(&bitmap->lock, flags); return 0; } - page_cache_get(bitmap->sb_page); spin_unlock_irqrestore(&bitmap->lock, flags); sb = (bitmap_super_t *)kmap(bitmap->sb_page); sb->events = cpu_to_le64(bitmap->mddev->events); if (!bitmap->mddev->degraded) sb->events_cleared = cpu_to_le64(bitmap->mddev->events); kunmap(bitmap->sb_page); - return write_page(bitmap->sb_page, 0); + return write_page(bitmap, bitmap->sb_page, 0); } /* print out the bitmap file superblock */ @@ -556,10 +558,10 @@ static void bitmap_file_unmap(struct bitmap *bitmap) static void bitmap_stop_daemons(struct bitmap *bitmap); /* dequeue the next item in a page list -- don't call from irq context */ -static struct page_list *dequeue_page(struct bitmap *bitmap, - struct list_head *head) +static struct page_list *dequeue_page(struct bitmap *bitmap) { struct page_list *item = NULL; + struct list_head *head = &bitmap->complete_pages; spin_lock(&bitmap->write_lock); if (list_empty(head)) @@ -573,23 +575,15 @@ out: static void drain_write_queues(struct bitmap *bitmap) { - struct list_head *queues[] = { &bitmap->complete_pages, NULL }; - struct list_head *head; struct page_list *item; - int i; - for (i = 0; queues[i]; i++) { - head = queues[i]; - while ((item = dequeue_page(bitmap, head))) { - page_cache_release(item->page); - mempool_free(item, bitmap->write_pool); - } + while ((item = dequeue_page(bitmap))) { + /* don't bother to wait */ + page_cache_release(item->page); + mempool_free(item, bitmap->write_pool); } - spin_lock(&bitmap->write_lock); - bitmap->writes_pending = 0; /* make sure waiters continue */ wake_up(&bitmap->write_wait); - spin_unlock(&bitmap->write_lock); } static void bitmap_file_put(struct bitmap *bitmap) @@ -734,13 +728,13 @@ int bitmap_unplug(struct bitmap *bitmap) spin_unlock_irqrestore(&bitmap->lock, flags); if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) - if (write_page(page, 0)) + if (write_page(bitmap, page, 0)) return 1; } if (wait) { /* if any writes were performed, we need to wait on them */ spin_lock_irq(&bitmap->write_lock); wait_event_lock_irq(bitmap->write_wait, - bitmap->writes_pending == 0, bitmap->write_lock, + list_empty(&bitmap->complete_pages), bitmap->write_lock, wake_up_process(bitmap->writeback_daemon->tsk)); spin_unlock_irq(&bitmap->write_lock); } @@ -841,7 +835,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, int in_sync) */ memset(page_address(page) + offset, 0xff, PAGE_SIZE - offset); - ret = write_page(page, 1); + ret = write_page(bitmap, page, 1); if (ret) { kunmap(page); /* release, page not in filemap yet */ @@ -934,7 +928,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) } spin_unlock_irqrestore(&bitmap->lock, flags); if (attr & BITMAP_PAGE_NEEDWRITE) { - if (write_page(page, 0)) + if (write_page(bitmap, page, 0)) bitmap_file_kick(bitmap); page_cache_release(page); } @@ -950,7 +944,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) { clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); - err = write_page(lastpage, 0); + err = write_page(bitmap, lastpage, 0); } else { set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); @@ -998,7 +992,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) { clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); - err = write_page(lastpage, 0); + err = write_page(bitmap, lastpage, 0); } else { set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); @@ -1034,46 +1028,40 @@ static void bitmap_writeback_daemon(mddev_t *mddev) struct page_list *item; int err = 0; - while (1) { - PRINTK("%s: bitmap writeback daemon waiting...\n", bmname(bitmap)); - down_interruptible(&bitmap->write_done); - if (signal_pending(current)) { - printk(KERN_INFO - "%s: bitmap writeback daemon got signal, exiting...\n", - bmname(bitmap)); - break; - } + if (signal_pending(current)) { + printk(KERN_INFO + "%s: bitmap writeback daemon got signal, exiting...\n", + bmname(bitmap)); + err = -EINTR; + goto out; + } - PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap)); - /* wait on bitmap page writebacks */ - while ((item = dequeue_page(bitmap, &bitmap->complete_pages))) { - page = item->page; - mempool_free(item, bitmap->write_pool); - PRINTK("wait on page writeback: %p %lu\n", page, bitmap->writes_pending); - wait_on_page_writeback(page); - PRINTK("finished page writeback: %p %lu\n", page, bitmap->writes_pending); - spin_lock(&bitmap->write_lock); - if (!--bitmap->writes_pending) - wake_up(&bitmap->write_wait); - spin_unlock(&bitmap->write_lock); - err = PageError(page); - page_cache_release(page); - if (err) { - printk(KERN_WARNING "%s: bitmap file writeback " - "failed (page %lu): %d\n", - bmname(bitmap), page->index, err); - bitmap_file_kick(bitmap); - goto out; - } + PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap)); + /* wait on bitmap page writebacks */ + while ((item = dequeue_page(bitmap))) { + page = item->page; + mempool_free(item, bitmap->write_pool); + PRINTK("wait on page writeback: %p\n", page); + wait_on_page_writeback(page); + PRINTK("finished page writeback: %p\n", page); + + err = PageError(page); + page_cache_release(page); + if (err) { + printk(KERN_WARNING "%s: bitmap file writeback " + "failed (page %lu): %d\n", + bmname(bitmap), page->index, err); + bitmap_file_kick(bitmap); + goto out; } } -out: + out: + wake_up(&bitmap->write_wait); if (err) { printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n", - bmname(bitmap), err); + bmname(bitmap), err); daemon_exit(bitmap, &bitmap->writeback_daemon); } - return; } static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr, @@ -1375,7 +1363,7 @@ int bitmap_setallbits(struct bitmap *bitmap) spin_unlock_irqrestore(&bitmap->lock, flags); memset(kmap(page), 0xff, PAGE_SIZE); kunmap(page); - if (write_page(page, 0)) + if (write_page(bitmap, page, 0)) return 1; } @@ -1443,7 +1431,6 @@ int bitmap_create(mddev_t *mddev) mddev->bitmap = bitmap; spin_lock_init(&bitmap->write_lock); - init_MUTEX_LOCKED(&bitmap->write_done); INIT_LIST_HEAD(&bitmap->complete_pages); init_waitqueue_head(&bitmap->write_wait); bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc, diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h index f785cf2..cfe60cf 100644 --- a/include/linux/raid/bitmap.h +++ b/include/linux/raid/bitmap.h @@ -233,21 +233,12 @@ struct bitmap { unsigned long daemon_sleep; /* how many seconds between updates? */ /* - * bitmap write daemon - this daemon performs writes to the bitmap file - * this thread is only needed because of a limitation in ext3 (jbd) - * that does not allow a task to have two journal transactions ongoing - * simultaneously (even if the transactions are for two different - * filesystems) -- in the case of bitmap, that would be the filesystem - * that the bitmap file resides on and the filesystem that is mounted - * on the md device -- see current->journal_info in jbd/transaction.c + * bitmap_writeback_daemon waits for file-pages that have been written, + * as there is no way to get a call-back when a page write completes. */ mdk_thread_t *writeback_daemon; spinlock_t write_lock; - struct semaphore write_ready; - struct semaphore write_done; - unsigned long writes_pending; wait_queue_head_t write_wait; - struct list_head write_pages; struct list_head complete_pages; mempool_t *write_pool; }; -- cgit v0.10.2 From aa3163f81654fa057039258e32a6811147bf0c14 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:22 -0700 Subject: [PATCH] md: don't skip bitmap pages due to lack of bit that we just cleared. When looking for pages that need cleaning we skip pages that don't have BITMAP_PAGE_CLEAN set. But if it is the 'current' page we will have cleared that bit ourselves, so skipping it is wrong. So: move the 'skip this page' inside 'if page != lastpage'. Also fold call of file_page_offset into the one place where the value (bit) is used. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 86b6b03..204564d 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -897,7 +897,7 @@ static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, int bitmap_daemon_work(struct bitmap *bitmap) { - unsigned long bit, j; + unsigned long j; unsigned long flags; struct page *page = NULL, *lastpage = NULL; int err = 0; @@ -920,24 +920,23 @@ int bitmap_daemon_work(struct bitmap *bitmap) } page = filemap_get_page(bitmap, j); - /* skip this page unless it's marked as needing cleaning */ - if (!((attr=get_page_attr(bitmap, page)) & BITMAP_PAGE_CLEAN)) { - if (attr & BITMAP_PAGE_NEEDWRITE) { - page_cache_get(page); - clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); - } - spin_unlock_irqrestore(&bitmap->lock, flags); - if (attr & BITMAP_PAGE_NEEDWRITE) { - if (write_page(bitmap, page, 0)) - bitmap_file_kick(bitmap); - page_cache_release(page); - } - continue; - } - - bit = file_page_offset(j); if (page != lastpage) { + /* skip this page unless it's marked as needing cleaning */ + if (!((attr=get_page_attr(bitmap, page)) & BITMAP_PAGE_CLEAN)) { + if (attr & BITMAP_PAGE_NEEDWRITE) { + page_cache_get(page); + clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); + } + spin_unlock_irqrestore(&bitmap->lock, flags); + if (attr & BITMAP_PAGE_NEEDWRITE) { + if (write_page(bitmap, page, 0)) + bitmap_file_kick(bitmap); + page_cache_release(page); + } + continue; + } + /* grab the new page, sync and release the old */ page_cache_get(page); if (lastpage != NULL) { @@ -979,7 +978,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) -1); /* clear the bit */ - clear_bit(bit, page_address(page)); + clear_bit(file_page_offset(j), page_address(page)); } } spin_unlock_irqrestore(&bitmap->lock, flags); -- cgit v0.10.2 From 191ea9b2c7cc3ebbe0678834ab710d7d95ad3f9a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:23 -0700 Subject: [PATCH] md: raid1 support for bitmap intent logging Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 3c5c916..0fd4c3b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -12,6 +12,15 @@ * Fixes to reconstruction by Jakob Østergaard" * Various fixes by Neil Brown * + * Changes by Peter T. Breuer 31/1/2003 to support + * bitmapped intelligence in resync: + * + * - bitmap marked during normal i/o + * - bitmap used to skip nondirty blocks during sync + * + * Additions to bitmap code, (C) 2003-2004 Paul Clements, SteelEye Technology: + * - persistent bitmap code + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -22,7 +31,16 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "dm-bio-list.h" #include +#include + +#define DEBUG 0 +#if DEBUG +#define PRINTK(x...) printk(x) +#else +#define PRINTK(x...) +#endif /* * Number of guaranteed r1bios in case of extreme VM load: @@ -287,9 +305,11 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int /* * this branch is our 'one mirror IO has finished' event handler: */ - if (!uptodate) + if (!uptodate) { md_error(r1_bio->mddev, conf->mirrors[mirror].rdev); - else + /* an I/O failed, we can't clear the bitmap */ + set_bit(R1BIO_Degraded, &r1_bio->state); + } else /* * Set R1BIO_Uptodate in our master bio, so that * we will return a good error code for to the higher @@ -309,6 +329,10 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int * already. */ if (atomic_dec_and_test(&r1_bio->remaining)) { + /* clear the bitmap if all writes complete successfully */ + bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, + r1_bio->sectors, + !test_bit(R1BIO_Degraded, &r1_bio->state)); md_write_end(r1_bio->mddev); raid_end_bio_io(r1_bio); } @@ -458,7 +482,10 @@ static void unplug_slaves(mddev_t *mddev) static void raid1_unplug(request_queue_t *q) { - unplug_slaves(q->queuedata); + mddev_t *mddev = q->queuedata; + + unplug_slaves(mddev); + md_wakeup_thread(mddev->thread); } static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk, @@ -501,16 +528,16 @@ static void device_barrier(conf_t *conf, sector_t sect) { spin_lock_irq(&conf->resync_lock); wait_event_lock_irq(conf->wait_idle, !waitqueue_active(&conf->wait_resume), - conf->resync_lock, unplug_slaves(conf->mddev)); + conf->resync_lock, raid1_unplug(conf->mddev->queue)); if (!conf->barrier++) { wait_event_lock_irq(conf->wait_idle, !conf->nr_pending, - conf->resync_lock, unplug_slaves(conf->mddev)); + conf->resync_lock, raid1_unplug(conf->mddev->queue)); if (conf->nr_pending) BUG(); } wait_event_lock_irq(conf->wait_resume, conf->barrier < RESYNC_DEPTH, - conf->resync_lock, unplug_slaves(conf->mddev)); + conf->resync_lock, raid1_unplug(conf->mddev->queue)); conf->next_resync = sect; spin_unlock_irq(&conf->resync_lock); } @@ -522,8 +549,12 @@ static int make_request(request_queue_t *q, struct bio * bio) mirror_info_t *mirror; r1bio_t *r1_bio; struct bio *read_bio; - int i, disks; + int i, targets = 0, disks; mdk_rdev_t *rdev; + struct bitmap *bitmap = mddev->bitmap; + unsigned long flags; + struct bio_list bl; + /* * Register the new request and wait if the reconstruction @@ -554,7 +585,7 @@ static int make_request(request_queue_t *q, struct bio * bio) r1_bio->master_bio = bio; r1_bio->sectors = bio->bi_size >> 9; - + r1_bio->state = 0; r1_bio->mddev = mddev; r1_bio->sector = bio->bi_sector; @@ -597,6 +628,13 @@ static int make_request(request_queue_t *q, struct bio * bio) * bios[x] to bio */ disks = conf->raid_disks; +#if 0 + { static int first=1; + if (first) printk("First Write sector %llu disks %d\n", + (unsigned long long)r1_bio->sector, disks); + first = 0; + } +#endif rcu_read_lock(); for (i = 0; i < disks; i++) { if ((rdev=conf->mirrors[i].rdev) != NULL && @@ -607,13 +645,21 @@ static int make_request(request_queue_t *q, struct bio * bio) r1_bio->bios[i] = NULL; } else r1_bio->bios[i] = bio; + targets++; } else r1_bio->bios[i] = NULL; } rcu_read_unlock(); - atomic_set(&r1_bio->remaining, 1); + if (targets < conf->raid_disks) { + /* array is degraded, we will not clear the bitmap + * on I/O completion (see raid1_end_write_request) */ + set_bit(R1BIO_Degraded, &r1_bio->state); + } + + atomic_set(&r1_bio->remaining, 0); + bio_list_init(&bl); for (i = 0; i < disks; i++) { struct bio *mbio; if (!r1_bio->bios[i]) @@ -629,14 +675,23 @@ static int make_request(request_queue_t *q, struct bio * bio) mbio->bi_private = r1_bio; atomic_inc(&r1_bio->remaining); - generic_make_request(mbio); - } - if (atomic_dec_and_test(&r1_bio->remaining)) { - md_write_end(mddev); - raid_end_bio_io(r1_bio); + bio_list_add(&bl, mbio); } + bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors); + spin_lock_irqsave(&conf->device_lock, flags); + bio_list_merge(&conf->pending_bio_list, &bl); + bio_list_init(&bl); + + blk_plug_device(mddev->queue); + spin_unlock_irqrestore(&conf->device_lock, flags); + +#if 0 + while ((bio = bio_list_pop(&bl)) != NULL) + generic_make_request(bio); +#endif + return 0; } @@ -716,7 +771,7 @@ static void close_sync(conf_t *conf) { spin_lock_irq(&conf->resync_lock); wait_event_lock_irq(conf->wait_resume, !conf->barrier, - conf->resync_lock, unplug_slaves(conf->mddev)); + conf->resync_lock, raid1_unplug(conf->mddev->queue)); spin_unlock_irq(&conf->resync_lock); if (conf->barrier) BUG(); @@ -830,10 +885,11 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) * or re-read if the read failed. * We don't do much here, just schedule handling by raid1d */ - if (!uptodate) + if (!uptodate) { md_error(r1_bio->mddev, conf->mirrors[r1_bio->read_disk].rdev); - else + set_bit(R1BIO_Degraded, &r1_bio->state); + } else set_bit(R1BIO_Uptodate, &r1_bio->state); rdev_dec_pending(conf->mirrors[r1_bio->read_disk].rdev, conf->mddev); reschedule_retry(r1_bio); @@ -857,8 +913,10 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) mirror = i; break; } - if (!uptodate) + if (!uptodate) { md_error(mddev, conf->mirrors[mirror].rdev); + set_bit(R1BIO_Degraded, &r1_bio->state); + } update_head_pos(mirror, r1_bio); if (atomic_dec_and_test(&r1_bio->remaining)) { @@ -878,6 +936,9 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) bio = r1_bio->bios[r1_bio->read_disk]; +/* + if (r1_bio->sector == 0) printk("First sync write startss\n"); +*/ /* * schedule writes */ @@ -905,10 +966,12 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) atomic_inc(&conf->mirrors[i].rdev->nr_pending); atomic_inc(&r1_bio->remaining); md_sync_acct(conf->mirrors[i].rdev->bdev, wbio->bi_size >> 9); + generic_make_request(wbio); } if (atomic_dec_and_test(&r1_bio->remaining)) { + /* if we're here, all write(s) have completed, so clean up */ md_done_sync(mddev, r1_bio->sectors, 1); put_buf(r1_bio); } @@ -937,6 +1000,26 @@ static void raid1d(mddev_t *mddev) for (;;) { char b[BDEVNAME_SIZE]; spin_lock_irqsave(&conf->device_lock, flags); + + if (conf->pending_bio_list.head) { + bio = bio_list_get(&conf->pending_bio_list); + blk_remove_plug(mddev->queue); + spin_unlock_irqrestore(&conf->device_lock, flags); + /* flush any pending bitmap writes to disk before proceeding w/ I/O */ + if (bitmap_unplug(mddev->bitmap) != 0) + printk("%s: bitmap file write failed!\n", mdname(mddev)); + + while (bio) { /* submit pending writes */ + struct bio *next = bio->bi_next; + bio->bi_next = NULL; + generic_make_request(bio); + bio = next; + } + unplug = 1; + + continue; + } + if (list_empty(head)) break; r1_bio = list_entry(head->prev, r1bio_t, retry_list); @@ -1020,17 +1103,43 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i int disk; int i; int write_targets = 0; + int sync_blocks; if (!conf->r1buf_pool) + { +/* + printk("sync start - bitmap %p\n", mddev->bitmap); +*/ if (init_resync(conf)) return 0; + } max_sector = mddev->size << 1; if (sector_nr >= max_sector) { + /* If we aborted, we need to abort the + * sync on the 'current' bitmap chunk (there will + * only be one in raid1 resync. + * We can find the current addess in mddev->curr_resync + */ + if (!conf->fullsync) { + if (mddev->curr_resync < max_sector) + bitmap_end_sync(mddev->bitmap, + mddev->curr_resync, + &sync_blocks, 1); + bitmap_close_sync(mddev->bitmap); + } + if (mddev->curr_resync >= max_sector) + conf->fullsync = 0; close_sync(conf); return 0; } + if (!conf->fullsync && + !bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks)) { + /* We can skip this block, and probably several more */ + *skipped = 1; + return sync_blocks; + } /* * If there is non-resync activity waiting for us then * put in a delay to throttle resync. @@ -1069,6 +1178,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i r1_bio->mddev = mddev; r1_bio->sector = sector_nr; + r1_bio->state = 0; set_bit(R1BIO_IsSync, &r1_bio->state); r1_bio->read_disk = disk; @@ -1103,6 +1213,11 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i bio->bi_bdev = conf->mirrors[i].rdev->bdev; bio->bi_private = r1_bio; } + + if (write_targets + 1 < conf->raid_disks) + /* array degraded, can't clear bitmap */ + set_bit(R1BIO_Degraded, &r1_bio->state); + if (write_targets == 0) { /* There is nowhere to write, so all non-sync * drives must be failed - so we are finished @@ -1122,6 +1237,14 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i len = (max_sector - sector_nr) << 9; if (len == 0) break; + if (!conf->fullsync && sync_blocks == 0) + if (!bitmap_start_sync(mddev->bitmap, + sector_nr, &sync_blocks)) + break; + if (sync_blocks < (PAGE_SIZE>>9)) + BUG(); + if (len > (sync_blocks<<9)) len = sync_blocks<<9; + for (i=0 ; i < conf->raid_disks; i++) { bio = r1_bio->bios[i]; if (bio->bi_end_io) { @@ -1144,6 +1267,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i } nr_sectors += len>>9; sector_nr += len>>9; + sync_blocks -= (len>>9); } while (r1_bio->bios[disk]->bi_vcnt < RESYNC_PAGES); bio_full: bio = r1_bio->bios[disk]; @@ -1232,6 +1356,9 @@ static int run(mddev_t *mddev) init_waitqueue_head(&conf->wait_idle); init_waitqueue_head(&conf->wait_resume); + bio_list_init(&conf->pending_bio_list); + bio_list_init(&conf->flushing_bio_list); + if (!conf->working_disks) { printk(KERN_ERR "raid1: no operational mirrors for %s\n", mdname(mddev)); @@ -1260,16 +1387,15 @@ static int run(mddev_t *mddev) conf->last_used = j; - - { - mddev->thread = md_register_thread(raid1d, mddev, "%s_raid1"); - if (!mddev->thread) { - printk(KERN_ERR - "raid1: couldn't allocate thread for %s\n", - mdname(mddev)); - goto out_free_conf; - } + mddev->thread = md_register_thread(raid1d, mddev, "%s_raid1"); + if (!mddev->thread) { + printk(KERN_ERR + "raid1: couldn't allocate thread for %s\n", + mdname(mddev)); + goto out_free_conf; } + if (mddev->bitmap) mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ; + printk(KERN_INFO "raid1: raid set %s active with %d out of %d mirrors\n", mdname(mddev), mddev->raid_disks - mddev->degraded, @@ -1394,7 +1520,7 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks) spin_lock_irq(&conf->resync_lock); conf->barrier++; wait_event_lock_irq(conf->wait_idle, !conf->nr_pending, - conf->resync_lock, unplug_slaves(mddev)); + conf->resync_lock, raid1_unplug(mddev->queue)); spin_unlock_irq(&conf->resync_lock); /* ok, everything is stopped */ diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h index abbfdd9..9d93cf1 100644 --- a/include/linux/raid/raid1.h +++ b/include/linux/raid/raid1.h @@ -36,12 +36,21 @@ struct r1_private_data_s { spinlock_t device_lock; struct list_head retry_list; + /* queue pending writes and submit them on unplug */ + struct bio_list pending_bio_list; + /* queue of writes that have been unplugged */ + struct bio_list flushing_bio_list; + /* for use when syncing mirrors: */ spinlock_t resync_lock; - int nr_pending; - int barrier; + int nr_pending; + int barrier; sector_t next_resync; + int fullsync; /* set to 1 if a full sync is needed, + * (fresh device added). + * Cleared when a sync completes. + */ wait_queue_head_t wait_idle; wait_queue_head_t wait_resume; @@ -85,14 +94,17 @@ struct r1bio_s { int read_disk; struct list_head retry_list; + struct bitmap_update *bitmap_update; /* * if the IO is in WRITE direction, then multiple bios are used. * We choose the number when they are allocated. */ struct bio *bios[0]; + /* DO NOT PUT ANY NEW FIELDS HERE - bios array is contiguously alloced*/ }; /* bits for r1bio.state */ #define R1BIO_Uptodate 0 #define R1BIO_IsSync 1 +#define R1BIO_Degraded 2 #endif -- cgit v0.10.2 From ab7a30c7051ee32d0d72415fe0a16d60eba38a0d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:23 -0700 Subject: [PATCH] md: fix bug when raid1 attempts a partial reconstruct. The logic here is wrong. if fullsync is 0, it WILL BUG. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 0fd4c3b..9d9acc3 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1237,13 +1237,16 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i len = (max_sector - sector_nr) << 9; if (len == 0) break; - if (!conf->fullsync && sync_blocks == 0) - if (!bitmap_start_sync(mddev->bitmap, - sector_nr, &sync_blocks)) - break; - if (sync_blocks < (PAGE_SIZE>>9)) - BUG(); - if (len > (sync_blocks<<9)) len = sync_blocks<<9; + if (!conf->fullsync) { + if (sync_blocks == 0) { + if (!bitmap_start_sync(mddev->bitmap, + sector_nr, &sync_blocks)) + break; + if (sync_blocks < (PAGE_SIZE>>9)) + BUG(); + if (len > (sync_blocks<<9)) len = sync_blocks<<9; + } + } for (i=0 ; i < conf->raid_disks; i++) { bio = r1_bio->bios[i]; -- cgit v0.10.2 From 289e99e8ed8f36e386bf7de49947311c17ae1482 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:24 -0700 Subject: [PATCH] md: initialise sync_blocks in raid1 resync Otherwise it could have a random value and might BUG. This fixes a BUG during resync problem in raid1 introduced by the bitmap-based-intent-loggin patches. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 9d9acc3..c3b4772 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1230,6 +1230,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i } nr_sectors = 0; + sync_blocks = 0; do { struct page *page; int len = PAGE_SIZE; -- cgit v0.10.2 From 41158c7eb22312cfaa256744e1553bb4042ff085 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:25 -0700 Subject: [PATCH] md: optimise reconstruction when re-adding a recently failed drive. When an array is degraded, bit in the intent-bitmap are never cleared. So if a recently failed drive is re-added, we only need to reconstruct the block that are still reflected in the bitmap. This patch adds support for this re-adding. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/md.c b/drivers/md/md.c index b02f8d1..789b114 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -577,6 +577,8 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) mdp_disk_t *desc; mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page); + rdev->raid_disk = -1; + rdev->in_sync = 0; if (mddev->raid_disks == 0) { mddev->major_version = 0; mddev->minor_version = sb->minor_version; @@ -607,16 +609,24 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) memcpy(mddev->uuid+12,&sb->set_uuid3, 4); mddev->max_disks = MD_SB_DISKS; - } else { - __u64 ev1; - ev1 = md_event(sb); + } else if (mddev->pers == NULL) { + /* Insist on good event counter while assembling */ + __u64 ev1 = md_event(sb); ++ev1; if (ev1 < mddev->events) return -EINVAL; - } + } else if (mddev->bitmap) { + /* if adding to array with a bitmap, then we can accept an + * older device ... but not too old. + */ + __u64 ev1 = md_event(sb); + if (ev1 < mddev->bitmap->events_cleared) + return 0; + } else /* just a hot-add of a new device, leave raid_disk at -1 */ + return 0; + if (mddev->level != LEVEL_MULTIPATH) { - rdev->raid_disk = -1; - rdev->in_sync = rdev->faulty = 0; + rdev->faulty = 0; desc = sb->disks + rdev->desc_nr; if (desc->state & (1<in_sync = 1; rdev->raid_disk = desc->raid_disk; } - } + } else /* MULTIPATH are always insync */ + rdev->in_sync = 1; return 0; } @@ -868,6 +879,8 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) { struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page); + rdev->raid_disk = -1; + rdev->in_sync = 0; if (mddev->raid_disks == 0) { mddev->major_version = 1; mddev->patch_version = 0; @@ -885,13 +898,21 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) memcpy(mddev->uuid, sb->set_uuid, 16); mddev->max_disks = (4096-256)/2; - } else { - __u64 ev1; - ev1 = le64_to_cpu(sb->events); + } else if (mddev->pers == NULL) { + /* Insist of good event counter while assembling */ + __u64 ev1 = le64_to_cpu(sb->events); ++ev1; if (ev1 < mddev->events) return -EINVAL; - } + } else if (mddev->bitmap) { + /* If adding to array with a bitmap, then we can accept an + * older device, but not too old. + */ + __u64 ev1 = le64_to_cpu(sb->events); + if (ev1 < mddev->bitmap->events_cleared) + return 0; + } else /* just a hot-add of a new device, leave raid_disk at -1 */ + return 0; if (mddev->level != LEVEL_MULTIPATH) { int role; @@ -899,14 +920,10 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]); switch(role) { case 0xffff: /* spare */ - rdev->in_sync = 0; rdev->faulty = 0; - rdev->raid_disk = -1; break; case 0xfffe: /* faulty */ - rdev->in_sync = 0; rdev->faulty = 1; - rdev->raid_disk = -1; break; default: rdev->in_sync = 1; @@ -914,7 +931,9 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) rdev->raid_disk = role; break; } - } + } else /* MULTIPATH are always insync */ + rdev->in_sync = 1; + return 0; } @@ -2155,6 +2174,18 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) PTR_ERR(rdev)); return PTR_ERR(rdev); } + /* set save_raid_disk if appropriate */ + if (!mddev->persistent) { + if (info->state & (1<raid_disk < mddev->raid_disks) + rdev->raid_disk = info->raid_disk; + else + rdev->raid_disk = -1; + } else + super_types[mddev->major_version]. + validate_super(mddev, rdev); + rdev->saved_raid_disk = rdev->raid_disk; + rdev->in_sync = 0; /* just to be sure */ rdev->raid_disk = -1; err = bind_rdev_to_array(rdev, mddev); @@ -3706,6 +3737,14 @@ void md_check_recovery(mddev_t *mddev) mddev->pers->spare_active(mddev); } md_update_sb(mddev); + + /* if array is no-longer degraded, then any saved_raid_disk + * information must be scrapped + */ + if (!mddev->degraded) + ITERATE_RDEV(mddev,rdev,rtmp) + rdev->saved_raid_disk = -1; + mddev->recovery = 0; /* flag recovery needed just to double check */ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index c3b4772..3f5234f 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -811,9 +811,12 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) { conf_t *conf = mddev->private; int found = 0; - int mirror; + int mirror = 0; mirror_info_t *p; + if (rdev->saved_raid_disk >= 0 && + conf->mirrors[rdev->saved_raid_disk].rdev == NULL) + mirror = rdev->saved_raid_disk; for (mirror=0; mirror < mddev->raid_disks; mirror++) if ( !(p=conf->mirrors+mirror)->rdev) { @@ -830,6 +833,8 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) p->head_position = 0; rdev->raid_disk = mirror; found = 1; + if (rdev->saved_raid_disk != mirror) + conf->fullsync = 1; p->rdev = rdev; break; } diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 16e94a9..6cdcb44 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -183,6 +183,10 @@ struct mdk_rdev_s int desc_nr; /* descriptor index in the superblock */ int raid_disk; /* role of device in array */ + int saved_raid_disk; /* role that device used to have in the + * array and could again if we did a partial + * resync from the bitmap + */ atomic_t nr_pending; /* number of pending requests. * only maintained for arrays that -- cgit v0.10.2 From 3d310eb7b3df1252e8595d059d982b0a9825a137 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:26 -0700 Subject: [PATCH] md: fix deadlock due to md thread processing delayed requests. Before completing a 'write' the md superblock might need to be updated. This is best done by the md_thread. The current code schedules this up and queues the write request for later handling by the md_thread. However some personalities (Raid5/raid6) will deadlock if the md_thread tries to submit requests to its own array. So this patch changes things so the processes submitting the request waits for the superblock to be written and then submits the request itself. This fixes a recently-created deadlock in raid5/raid6 Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/md.c b/drivers/md/md.c index 789b114..7075beb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -224,8 +224,8 @@ static mddev_t * mddev_find(dev_t unit) INIT_LIST_HEAD(&new->all_mddevs); init_timer(&new->safemode_timer); atomic_set(&new->active, 1); - bio_list_init(&new->write_list); spin_lock_init(&new->write_lock); + init_waitqueue_head(&new->sb_wait); new->queue = blk_alloc_queue(GFP_KERNEL); if (!new->queue) { @@ -1307,6 +1307,7 @@ repeat: if (!mddev->persistent) { mddev->sb_dirty = 0; spin_unlock(&mddev->write_lock); + wake_up(&mddev->sb_wait); return; } spin_unlock(&mddev->write_lock); @@ -1348,6 +1349,7 @@ repeat: } mddev->sb_dirty = 0; spin_unlock(&mddev->write_lock); + wake_up(&mddev->sb_wait); } @@ -3368,29 +3370,26 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok) /* md_write_start(mddev, bi) * If we need to update some array metadata (e.g. 'active' flag - * in superblock) before writing, queue bi for later writing - * and return 0, else return 1 and it will be written now + * in superblock) before writing, schedule a superblock update + * and wait for it to complete. */ -int md_write_start(mddev_t *mddev, struct bio *bi) +void md_write_start(mddev_t *mddev, struct bio *bi) { + DEFINE_WAIT(w); if (bio_data_dir(bi) != WRITE) - return 1; + return; atomic_inc(&mddev->writes_pending); - spin_lock(&mddev->write_lock); - if (mddev->in_sync == 0 && mddev->sb_dirty == 0) { - spin_unlock(&mddev->write_lock); - return 1; - } - bio_list_add(&mddev->write_list, bi); - if (mddev->in_sync) { - mddev->in_sync = 0; - mddev->sb_dirty = 1; + spin_lock(&mddev->write_lock); + if (mddev->in_sync) { + mddev->in_sync = 0; + mddev->sb_dirty = 1; + md_wakeup_thread(mddev->thread); + } + spin_unlock(&mddev->write_lock); } - spin_unlock(&mddev->write_lock); - md_wakeup_thread(mddev->thread); - return 0; + wait_event(mddev->sb_wait, mddev->sb_dirty==0); } void md_write_end(mddev_t *mddev) @@ -3685,7 +3684,6 @@ void md_check_recovery(mddev_t *mddev) mddev->sb_dirty || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || test_bit(MD_RECOVERY_DONE, &mddev->recovery) || - mddev->write_list.head || (mddev->safemode == 1) || (mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending) && !mddev->in_sync && mddev->recovery_cp == MaxSector) @@ -3694,7 +3692,6 @@ void md_check_recovery(mddev_t *mddev) if (mddev_trylock(mddev)==0) { int spares =0; - struct bio *blist; spin_lock(&mddev->write_lock); if (mddev->safemode && !atomic_read(&mddev->writes_pending) && @@ -3704,21 +3701,11 @@ void md_check_recovery(mddev_t *mddev) } if (mddev->safemode == 1) mddev->safemode = 0; - blist = bio_list_get(&mddev->write_list); spin_unlock(&mddev->write_lock); if (mddev->sb_dirty) md_update_sb(mddev); - while (blist) { - struct bio *b = blist; - blist = blist->bi_next; - b->bi_next = NULL; - generic_make_request(b); - /* we already counted this, so need to un-count */ - md_write_end(mddev); - } - if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) && !test_bit(MD_RECOVERY_DONE, &mddev->recovery)) { diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 3f5234f..98b0977 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -561,8 +561,8 @@ static int make_request(request_queue_t *q, struct bio * bio) * thread has put up a bar for new requests. * Continue immediately if no resync is active currently. */ - if (md_write_start(mddev, bio)==0) - return 0; + md_write_start(mddev, bio); /* wait on superblock update early */ + spin_lock_irq(&conf->resync_lock); wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock, ); conf->nr_pending++; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 8476515..fd7324a 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -700,8 +700,7 @@ static int make_request(request_queue_t *q, struct bio * bio) return 0; } - if (md_write_start(mddev, bio) == 0) - return 0; + md_write_start(mddev, bio); /* * Register the new request and wait if the reconstruction diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 1ce3f5a..93a9726 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1411,8 +1411,7 @@ static int make_request (request_queue_t *q, struct bio * bi) sector_t logical_sector, last_sector; struct stripe_head *sh; - if (md_write_start(mddev, bi)==0) - return 0; + md_write_start(mddev, bi); if (bio_data_dir(bi)==WRITE) { disk_stat_inc(mddev->gendisk, writes); diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index d9c3854..f62ea1a 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -1570,8 +1570,7 @@ static int make_request (request_queue_t *q, struct bio * bi) sector_t logical_sector, last_sector; struct stripe_head *sh; - if (md_write_start(mddev, bi)==0) - return 0; + md_write_start(mddev, bi); if (bio_data_dir(bi)==WRITE) { disk_stat_inc(mddev->gendisk, writes); diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h index cfde8f4..75f41d8 100644 --- a/include/linux/raid/md.h +++ b/include/linux/raid/md.h @@ -69,7 +69,7 @@ extern mdk_thread_t * md_register_thread (void (*run) (mddev_t *mddev), extern void md_unregister_thread (mdk_thread_t *thread); extern void md_wakeup_thread(mdk_thread_t *thread); extern void md_check_recovery(mddev_t *mddev); -extern int md_write_start(mddev_t *mddev, struct bio *bi); +extern void md_write_start(mddev_t *mddev, struct bio *bi); extern void md_write_end(mddev_t *mddev); extern void md_handle_safemode(mddev_t *mddev); extern void md_done_sync(mddev_t *mddev, int blocks, int ok); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 6cdcb44..3e97702 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -261,7 +261,7 @@ struct mddev_s sector_t recovery_cp; spinlock_t write_lock; - struct bio_list write_list; + wait_queue_head_t sb_wait; /* for waiting on superblock updates */ unsigned int safemode; /* if set, update "clean" superblock * when no writes pending. -- cgit v0.10.2 From a654b9d8f851f4ca02649d5825cbe6c608adb10c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:27 -0700 Subject: [PATCH] md: allow md intent bitmap to be stored near the superblock. This provides an alternate to storing the bitmap in a separate file. The bitmap can be stored at a given offset from the superblock. Obviously the creator of the array must make sure this doesn't intersect with data.... After is good for version-0.90 superblocks. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 204564d..030d686 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -116,7 +116,7 @@ static unsigned char *bitmap_alloc_page(struct bitmap *bitmap) if (!page) printk("%s: bitmap_alloc_page FAILED\n", bmname(bitmap)); else - printk("%s: bitmap_alloc_page: allocated page at %p\n", + PRINTK("%s: bitmap_alloc_page: allocated page at %p\n", bmname(bitmap), page); return page; } @@ -258,13 +258,61 @@ char *file_path(struct file *file, char *buf, int count) * basic page I/O operations */ +/* IO operations when bitmap is stored near all superblocks */ +static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long index) +{ + /* choose a good rdev and read the page from there */ + + mdk_rdev_t *rdev; + struct list_head *tmp; + struct page *page = alloc_page(GFP_KERNEL); + sector_t target; + + if (!page) + return ERR_PTR(-ENOMEM); + do { + ITERATE_RDEV(mddev, rdev, tmp) + if (rdev->in_sync && !rdev->faulty) + goto found; + return ERR_PTR(-EIO); + + found: + target = (rdev->sb_offset << 1) + offset + index * (PAGE_SIZE/512); + + } while (!sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)); + + page->index = index; + return page; +} + +static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wait) +{ + mdk_rdev_t *rdev; + struct list_head *tmp; + + ITERATE_RDEV(mddev, rdev, tmp) + if (rdev->in_sync && !rdev->faulty) + md_super_write(mddev, rdev, + (rdev->sb_offset<<1) + offset + + page->index * (PAGE_SIZE/512), + PAGE_SIZE, + page); + + if (wait) + wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0); + return 0; +} + /* - * write out a page + * write out a page to a file */ static int write_page(struct bitmap *bitmap, struct page *page, int wait) { int ret = -ENOMEM; + if (bitmap->file == NULL) + return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); + lock_page(page); ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE); @@ -394,7 +442,12 @@ static int bitmap_read_sb(struct bitmap *bitmap) int err = -EINVAL; /* page 0 is the superblock, read it... */ - bitmap->sb_page = read_page(bitmap->file, 0, &bytes_read); + if (bitmap->file) + bitmap->sb_page = read_page(bitmap->file, 0, &bytes_read); + else { + bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0); + bytes_read = PAGE_SIZE; + } if (IS_ERR(bitmap->sb_page)) { err = PTR_ERR(bitmap->sb_page); bitmap->sb_page = NULL; @@ -625,14 +678,16 @@ static void bitmap_file_kick(struct bitmap *bitmap) bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET); bitmap_update_sb(bitmap); - path = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (path) - ptr = file_path(bitmap->file, path, PAGE_SIZE); + if (bitmap->file) { + path = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (path) + ptr = file_path(bitmap->file, path, PAGE_SIZE); - printk(KERN_ALERT "%s: kicking failed bitmap file %s from array!\n", - bmname(bitmap), ptr ? ptr : ""); + printk(KERN_ALERT "%s: kicking failed bitmap file %s from array!\n", + bmname(bitmap), ptr ? ptr : ""); - kfree(path); + kfree(path); + } bitmap_file_put(bitmap); @@ -676,7 +731,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) void *kaddr; unsigned long chunk = block >> CHUNK_BLOCK_SHIFT(bitmap); - if (!bitmap->file || !bitmap->filemap) { + if (!bitmap->filemap) { return; } @@ -715,7 +770,7 @@ int bitmap_unplug(struct bitmap *bitmap) * flushed out to disk */ for (i = 0; i < bitmap->file_pages; i++) { spin_lock_irqsave(&bitmap->lock, flags); - if (!bitmap->file || !bitmap->filemap) { + if (!bitmap->filemap) { spin_unlock_irqrestore(&bitmap->lock, flags); return 0; } @@ -732,11 +787,15 @@ int bitmap_unplug(struct bitmap *bitmap) return 1; } if (wait) { /* if any writes were performed, we need to wait on them */ - spin_lock_irq(&bitmap->write_lock); - wait_event_lock_irq(bitmap->write_wait, - list_empty(&bitmap->complete_pages), bitmap->write_lock, - wake_up_process(bitmap->writeback_daemon->tsk)); - spin_unlock_irq(&bitmap->write_lock); + if (bitmap->file) { + spin_lock_irq(&bitmap->write_lock); + wait_event_lock_irq(bitmap->write_wait, + list_empty(&bitmap->complete_pages), bitmap->write_lock, + wake_up_process(bitmap->writeback_daemon->tsk)); + spin_unlock_irq(&bitmap->write_lock); + } else + wait_event(bitmap->mddev->sb_wait, + atomic_read(&bitmap->mddev->pending_writes)==0); } return 0; } @@ -764,7 +823,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, int in_sync) chunks = bitmap->chunks; file = bitmap->file; - BUG_ON(!file); + BUG_ON(!file && !bitmap->offset); #if INJECT_FAULTS_3 outofdate = 1; @@ -779,7 +838,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, int in_sync) num_pages = (bytes + sizeof(bitmap_super_t) + PAGE_SIZE - 1) / PAGE_SIZE; - if (i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) { + if (file && i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) { printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n", bmname(bitmap), (unsigned long) i_size_read(file->f_mapping->host), @@ -816,14 +875,18 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, int in_sync) */ page = bitmap->sb_page; offset = sizeof(bitmap_super_t); - } else { + } else if (file) { page = read_page(file, index, &dummy); - if (IS_ERR(page)) { /* read error */ - ret = PTR_ERR(page); - goto out; - } + offset = 0; + } else { + page = read_sb_page(bitmap->mddev, bitmap->offset, index); offset = 0; } + if (IS_ERR(page)) { /* read error */ + ret = PTR_ERR(page); + goto out; + } + oldindex = index; oldpage = page; kmap(page); @@ -874,6 +937,19 @@ out: return ret; } +void bitmap_write_all(struct bitmap *bitmap) +{ + /* We don't actually write all bitmap blocks here, + * just flag them as needing to be written + */ + + unsigned long chunks = bitmap->chunks; + unsigned long bytes = (chunks+7)/8 + sizeof(bitmap_super_t); + unsigned long num_pages = (bytes + PAGE_SIZE-1) / PAGE_SIZE; + while (num_pages--) + bitmap->filemap_attr[num_pages] |= BITMAP_PAGE_NEEDWRITE; +} + static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) { @@ -913,7 +989,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) for (j = 0; j < bitmap->chunks; j++) { bitmap_counter_t *bmc; spin_lock_irqsave(&bitmap->lock, flags); - if (!bitmap->file || !bitmap->filemap) { + if (!bitmap->filemap) { /* error or shutdown */ spin_unlock_irqrestore(&bitmap->lock, flags); break; @@ -1072,6 +1148,7 @@ static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr, spin_lock_irqsave(&bitmap->lock, flags); *ptr = NULL; + if (!bitmap->file) /* no need for daemon if there's no backing file */ goto out_unlock; @@ -1416,9 +1493,11 @@ int bitmap_create(mddev_t *mddev) BUG_ON(sizeof(bitmap_super_t) != 256); - if (!file) /* bitmap disabled, nothing to do */ + if (!file && !mddev->bitmap_offset) /* bitmap disabled, nothing to do */ return 0; + BUG_ON(file && mddev->bitmap_offset); + bitmap = kmalloc(sizeof(*bitmap), GFP_KERNEL); if (!bitmap) return -ENOMEM; @@ -1438,7 +1517,8 @@ int bitmap_create(mddev_t *mddev) return -ENOMEM; bitmap->file = file; - get_file(file); + bitmap->offset = mddev->bitmap_offset; + if (file) get_file(file); /* read superblock from bitmap file (this sets bitmap->chunksize) */ err = bitmap_read_sb(bitmap); if (err) diff --git a/drivers/md/md.c b/drivers/md/md.c index 7075beb..fde8acf 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -337,7 +337,7 @@ static int bi_complete(struct bio *bio, unsigned int bytes_done, int error) return 0; } -static int sync_page_io(struct block_device *bdev, sector_t sector, int size, +int sync_page_io(struct block_device *bdev, sector_t sector, int size, struct page *page, int rw) { struct bio *bio = bio_alloc(GFP_NOIO, 1); @@ -609,6 +609,17 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) memcpy(mddev->uuid+12,&sb->set_uuid3, 4); mddev->max_disks = MD_SB_DISKS; + + if (sb->state & (1<bitmap_file == NULL) { + if (mddev->level != 1) { + /* FIXME use a better test */ + printk(KERN_WARNING "md: bitmaps only support for raid1\n"); + return -EINVAL; + } + mddev->bitmap_offset = (MD_SB_BYTES >> 9); + } + } else if (mddev->pers == NULL) { /* Insist on good event counter while assembling */ __u64 ev1 = md_event(sb); @@ -702,6 +713,9 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->layout = mddev->layout; sb->chunk_size = mddev->chunk_size; + if (mddev->bitmap && mddev->bitmap_file == NULL) + sb->state |= (1<disks[0].state = (1<uuid, sb->set_uuid, 16); mddev->max_disks = (4096-256)/2; + + if ((le32_to_cpu(sb->feature_map) & 1) && + mddev->bitmap_file == NULL ) { + if (mddev->level != 1) { + printk(KERN_WARNING "md: bitmaps only supported for raid1\n"); + return -EINVAL; + } + mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset); + } } else if (mddev->pers == NULL) { /* Insist of good event counter while assembling */ __u64 ev1 = le64_to_cpu(sb->events); @@ -960,6 +983,11 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) else sb->resync_offset = cpu_to_le64(0); + if (mddev->bitmap && mddev->bitmap_file == NULL) { + sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); + sb->feature_map = cpu_to_le32(1); + } + max_dev = 0; ITERATE_RDEV(mddev,rdev2,tmp) if (rdev2->desc_nr+1 > max_dev) @@ -2406,7 +2434,8 @@ static int set_bitmap_file(mddev_t *mddev, int fd) mdname(mddev)); fput(mddev->bitmap_file); mddev->bitmap_file = NULL; - } + } else + mddev->bitmap_offset = 0; /* file overrides offset */ return err; } @@ -3774,6 +3803,13 @@ void md_check_recovery(mddev_t *mddev) set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); if (!spares) set_bit(MD_RECOVERY_SYNC, &mddev->recovery); + if (spares && mddev->bitmap && ! mddev->bitmap->file) { + /* We are adding a device or devices to an array + * which has the bitmap stored on all devices. + * So make sure all bitmap pages get written + */ + bitmap_write_all(mddev->bitmap); + } mddev->sync_thread = md_register_thread(md_do_sync, mddev, "%s_resync"); diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h index cfe60cf..e24b74b 100644 --- a/include/linux/raid/bitmap.h +++ b/include/linux/raid/bitmap.h @@ -217,6 +217,7 @@ struct bitmap { /* bitmap spinlock */ spinlock_t lock; + long offset; /* offset from superblock if file is NULL */ struct file *file; /* backing disk file */ struct page *sb_page; /* cached copy of the bitmap file superblock */ struct page **filemap; /* list of cache pages for the file */ @@ -255,6 +256,7 @@ void bitmap_print_sb(struct bitmap *bitmap); int bitmap_update_sb(struct bitmap *bitmap); int bitmap_setallbits(struct bitmap *bitmap); +void bitmap_write_all(struct bitmap *bitmap); /* these are exported */ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors); diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h index 75f41d8..ffa316c 100644 --- a/include/linux/raid/md.h +++ b/include/linux/raid/md.h @@ -60,7 +60,14 @@ */ #define MD_MAJOR_VERSION 0 #define MD_MINOR_VERSION 90 -#define MD_PATCHLEVEL_VERSION 1 +/* + * MD_PATCHLEVEL_VERSION indicates kernel functionality. + * >=1 means different superblock formats are selectable using SET_ARRAY_INFO + * and major_version/minor_version accordingly + * >=2 means that Internal bitmaps are supported by setting MD_SB_BITMAP_PRESENT + * in the super status byte + */ +#define MD_PATCHLEVEL_VERSION 2 extern int register_md_personality (int p_num, mdk_personality_t *p); extern int unregister_md_personality (int p_num); @@ -78,6 +85,12 @@ extern void md_unplug_mddev(mddev_t *mddev); extern void md_print_devices (void); +extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, + sector_t sector, int size, struct page *page); +extern int sync_page_io(struct block_device *bdev, sector_t sector, int size, + struct page *page, int rw); + + #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); } #endif diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 3e97702..a3725b57 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -273,6 +273,10 @@ struct mddev_s struct bitmap *bitmap; /* the bitmap for the device */ struct file *bitmap_file; /* the bitmap file */ + long bitmap_offset; /* offset from superblock of + * start of bitmap. May be + * negative, but not '0' + */ struct list_head all_mddevs; }; diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h index 8ba95d6..8e592a2 100644 --- a/include/linux/raid/md_p.h +++ b/include/linux/raid/md_p.h @@ -96,6 +96,7 @@ typedef struct mdp_device_descriptor_s { #define MD_SB_CLEAN 0 #define MD_SB_ERRORS 1 +#define MD_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */ typedef struct mdp_superblock_s { /* * Constant generic information @@ -184,7 +185,7 @@ struct mdp_superblock_1 { /* constant array information - 128 bytes */ __u32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ __u32 major_version; /* 1 */ - __u32 feature_map; /* 0 for now */ + __u32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */ __u32 pad0; /* always set to 0 when writing */ __u8 set_uuid[16]; /* user-space generated. */ @@ -197,6 +198,10 @@ struct mdp_superblock_1 { __u32 chunksize; /* in 512byte sectors */ __u32 raid_disks; + __u32 bitmap_offset; /* sectors after start of superblock that bitmap starts + * NOTE: signed, so bitmap can be before superblock + * only meaningful of feature_map[0] is set. + */ __u8 pad1[128-96]; /* set to 0 when written */ /* constant this-device information - 64 bytes */ -- cgit v0.10.2 From 7bfa19f2748000d646dbdf8f48258cfe1d257b52 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:28 -0700 Subject: [PATCH] md: allow md to update multiple superblocks in parallel. currently, md updates all superblocks (one on each device) in series. It waits for one write to complete before starting the next. This isn't a big problem as superblock updates don't happen that often. However it is neater to do it in parallel, and if the drives in the array have gone to "sleep" after a period of idleness, then waking them is parallel is faster (and someone else should be worrying about power drain). Futher, we will need parallel superblock updates for a future patch which keeps the intent-logging bitmap near the superblock. Also remove the silly code that retired superblock updates 100 times. This simply never made sense. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/md.c b/drivers/md/md.c index fde8acf..ef3ad99 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -328,6 +328,40 @@ static void free_disk_sb(mdk_rdev_t * rdev) } +static int super_written(struct bio *bio, unsigned int bytes_done, int error) +{ + mdk_rdev_t *rdev = bio->bi_private; + if (bio->bi_size) + return 1; + + if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) + md_error(rdev->mddev, rdev); + + if (atomic_dec_and_test(&rdev->mddev->pending_writes)) + wake_up(&rdev->mddev->sb_wait); + return 0; +} + +void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, + sector_t sector, int size, struct page *page) +{ + /* write first size bytes of page to sector of rdev + * Increment mddev->pending_writes before returning + * and decrement it on completion, waking up sb_wait + * if zero is reached. + * If an error occurred, call md_error + */ + struct bio *bio = bio_alloc(GFP_NOIO, 1); + + bio->bi_bdev = rdev->bdev; + bio->bi_sector = sector; + bio_add_page(bio, page, size, 0); + bio->bi_private = rdev; + bio->bi_end_io = super_written; + atomic_inc(&mddev->pending_writes); + submit_bio((1<bi_size) @@ -1268,30 +1302,6 @@ void md_print_devices(void) } -static int write_disk_sb(mdk_rdev_t * rdev) -{ - char b[BDEVNAME_SIZE]; - if (!rdev->sb_loaded) { - MD_BUG(); - return 1; - } - if (rdev->faulty) { - MD_BUG(); - return 1; - } - - dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", - bdevname(rdev->bdev,b), - (unsigned long long)rdev->sb_offset); - - if (sync_page_io(rdev->bdev, rdev->sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE)) - return 0; - - printk("md: write_disk_sb failed for device %s\n", - bdevname(rdev->bdev,b)); - return 1; -} - static void sync_sbs(mddev_t * mddev) { mdk_rdev_t *rdev; @@ -1306,7 +1316,7 @@ static void sync_sbs(mddev_t * mddev) static void md_update_sb(mddev_t * mddev) { - int err, count = 100; + int err; struct list_head *tmp; mdk_rdev_t *rdev; int sync_req; @@ -1326,6 +1336,7 @@ repeat: MD_BUG(); mddev->events --; } + mddev->sb_dirty = 2; sync_sbs(mddev); /* @@ -1353,24 +1364,24 @@ repeat: dprintk("%s ", bdevname(rdev->bdev,b)); if (!rdev->faulty) { - err += write_disk_sb(rdev); + md_super_write(mddev,rdev, + rdev->sb_offset<<1, MD_SB_BYTES, + rdev->sb_page); + dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", + bdevname(rdev->bdev,b), + (unsigned long long)rdev->sb_offset); + } else dprintk(")\n"); - if (!err && mddev->level == LEVEL_MULTIPATH) + if (mddev->level == LEVEL_MULTIPATH) /* only need to write one superblock... */ break; } - if (err) { - if (--count) { - printk(KERN_ERR "md: errors occurred during superblock" - " update, repeating\n"); - goto repeat; - } - printk(KERN_ERR \ - "md: excessive errors occurred during superblock update, exiting\n"); - } + wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0); + /* if there was a failure, sb_dirty was set to 1, and we re-write super */ + spin_lock(&mddev->write_lock); - if (mddev->in_sync != sync_req) { + if (mddev->in_sync != sync_req|| mddev->sb_dirty == 1) { /* have to write it out again */ spin_unlock(&mddev->write_lock); goto repeat; diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index a3725b57..8c14ba5 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -262,6 +262,7 @@ struct mddev_s spinlock_t write_lock; wait_queue_head_t sb_wait; /* for waiting on superblock updates */ + atomic_t pending_writes; /* number of active superblock writes */ unsigned int safemode; /* if set, update "clean" superblock * when no writes pending. -- cgit v0.10.2 From 39730960d94306d7be414e8d54f4e5c071af1278 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:28 -0700 Subject: [PATCH] Two small fixes for md verion-1 superblocks. 1/ Must typecast int to (sector_t) before inverting or we might not invert enough bits. 2/ When "bitmap_offset" was added to mdp_superblock_1, we didn't increase the count of words-used (96 to 100). Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/md.c b/drivers/md/md.c index ef3ad99..65fab74a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -847,7 +847,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) case 0: sb_offset = rdev->bdev->bd_inode->i_size >> 9; sb_offset -= 8*2; - sb_offset &= ~(4*2-1); + sb_offset &= ~(sector_t)(4*2-1); /* convert from sectors to K */ sb_offset /= 2; break; diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h index 8e592a2..dc65cd4 100644 --- a/include/linux/raid/md_p.h +++ b/include/linux/raid/md_p.h @@ -202,7 +202,7 @@ struct mdp_superblock_1 { * NOTE: signed, so bitmap can be before superblock * only meaningful of feature_map[0] is set. */ - __u8 pad1[128-96]; /* set to 0 when written */ + __u8 pad1[128-100]; /* set to 0 when written */ /* constant this-device information - 64 bytes */ __u64 data_offset; /* sector start of data, often 0 */ -- cgit v0.10.2 From 8a5e9cf1d6626586ff08e49f400a006a9f0c3275 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:29 -0700 Subject: [PATCH] md: make sure md/bitmap doesn't try to write a page with active writeback Due to the use of write-behind, it is possible for md to write a page to the bitmap file that is still completing writeback. This is not allowed. With this patch, we detect those cases and either force a sync write, or back off and try later, as appropriate. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 030d686..95980ad 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -313,7 +313,16 @@ static int write_page(struct bitmap *bitmap, struct page *page, int wait) if (bitmap->file == NULL) return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); - lock_page(page); + if (wait) + lock_page(page); + else { + if (TestSetPageLocked(page)) + return -EAGAIN; /* already locked */ + if (PageWriteback(page)) { + unlock_page(page); + return -EAGAIN; + } + } ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE); if (!ret) @@ -400,7 +409,7 @@ int bitmap_update_sb(struct bitmap *bitmap) if (!bitmap->mddev->degraded) sb->events_cleared = cpu_to_le64(bitmap->mddev->events); kunmap(bitmap->sb_page); - return write_page(bitmap, bitmap->sb_page, 0); + return write_page(bitmap, bitmap->sb_page, 1); } /* print out the bitmap file superblock */ @@ -762,6 +771,7 @@ int bitmap_unplug(struct bitmap *bitmap) unsigned long i, attr, flags; struct page *page; int wait = 0; + int err; if (!bitmap) return 0; @@ -782,9 +792,17 @@ int bitmap_unplug(struct bitmap *bitmap) wait = 1; spin_unlock_irqrestore(&bitmap->lock, flags); - if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) - if (write_page(bitmap, page, 0)) + if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) { + err = write_page(bitmap, page, 0); + if (err == -EAGAIN) { + if (attr & BITMAP_PAGE_DIRTY) + err = write_page(bitmap, page, 1); + else + err = 0; + } + if (err) return 1; + } } if (wait) { /* if any writes were performed, we need to wait on them */ if (bitmap->file) { @@ -1006,8 +1024,15 @@ int bitmap_daemon_work(struct bitmap *bitmap) } spin_unlock_irqrestore(&bitmap->lock, flags); if (attr & BITMAP_PAGE_NEEDWRITE) { - if (write_page(bitmap, page, 0)) + switch (write_page(bitmap, page, 0)) { + case -EAGAIN: + set_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); + break; + case 0: + break; + default: bitmap_file_kick(bitmap); + } page_cache_release(page); } continue; @@ -1020,6 +1045,10 @@ int bitmap_daemon_work(struct bitmap *bitmap) clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); err = write_page(bitmap, lastpage, 0); + if (err == -EAGAIN) { + err = 0; + set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); + } } else { set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); @@ -1068,6 +1097,10 @@ int bitmap_daemon_work(struct bitmap *bitmap) clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); err = write_page(bitmap, lastpage, 0); + if (err == -EAGAIN) { + set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); + err = 0; + } } else { set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); @@ -1421,31 +1454,6 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, } } -/* dirty the entire bitmap */ -int bitmap_setallbits(struct bitmap *bitmap) -{ - unsigned long flags; - unsigned long j; - - /* dirty the in-memory bitmap */ - bitmap_set_memory_bits(bitmap, 0, bitmap->chunks << CHUNK_BLOCK_SHIFT(bitmap), 1); - - /* dirty the bitmap file */ - for (j = 0; j < bitmap->file_pages; j++) { - struct page *page = bitmap->filemap[j]; - - spin_lock_irqsave(&bitmap->lock, flags); - page_cache_get(page); - spin_unlock_irqrestore(&bitmap->lock, flags); - memset(kmap(page), 0xff, PAGE_SIZE); - kunmap(page); - if (write_page(bitmap, page, 0)) - return 1; - } - - return 0; -} - /* * free memory that was allocated */ -- cgit v0.10.2 From 990a8baf568ca1d0ae65e59783ff821794118d07 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 21 Jun 2005 17:17:30 -0700 Subject: [PATCH] md: remove unneeded NULL checks before kfree This patch removes some unneeded checks of pointers being NULL before calling kfree() on them. kfree() handles NULL pointers just fine, checking first is pointless. Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 0dd6c2b..d0a4bab 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -704,8 +704,7 @@ static void crypt_dtr(struct dm_target *ti) mempool_destroy(cc->page_pool); mempool_destroy(cc->io_pool); - if (cc->iv_mode) - kfree(cc->iv_mode); + kfree(cc->iv_mode); if (cc->iv_gen_ops && cc->iv_gen_ops->dtr) cc->iv_gen_ops->dtr(cc); crypto_free_tfm(cc->tfm); diff --git a/drivers/md/linear.c b/drivers/md/linear.c index b1941b8..8d74001 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -217,8 +217,7 @@ static int linear_run (mddev_t *mddev) return 0; out: - if (conf) - kfree(conf); + kfree(conf); return 1; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 65fab74a..0c6b5b6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -195,8 +195,7 @@ static mddev_t * mddev_find(dev_t unit) if (mddev->unit == unit) { mddev_get(mddev); spin_unlock(&all_mddevs_lock); - if (new) - kfree(new); + kfree(new); return mddev; } @@ -458,11 +457,8 @@ static int sb_equal(mdp_super_t *sb1, mdp_super_t *sb2) ret = 1; abort: - if (tmp1) - kfree(tmp1); - if (tmp2) - kfree(tmp2); - + kfree(tmp1); + kfree(tmp2); return ret; } diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 2ae2d70..2d2ca7f 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -533,8 +533,7 @@ static int multipath_run (mddev_t *mddev) out_free_conf: if (conf->pool) mempool_destroy(conf->pool); - if (conf->multipaths) - kfree(conf->multipaths); + kfree(conf->multipaths); kfree(conf); mddev->private = NULL; out: diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index e7d934e..e11dd14 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -371,10 +371,8 @@ static int raid0_run (mddev_t *mddev) return 0; out_free_conf: - if (conf->strip_zone) - kfree(conf->strip_zone); - if (conf->devlist) - kfree (conf->devlist); + kfree(conf->strip_zone); + kfree(conf->devlist); kfree(conf); mddev->private = NULL; out: @@ -386,11 +384,11 @@ static int raid0_stop (mddev_t *mddev) raid0_conf_t *conf = mddev_to_conf(mddev); blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ - kfree (conf->hash_table); + kfree(conf->hash_table); conf->hash_table = NULL; - kfree (conf->strip_zone); + kfree(conf->strip_zone); conf->strip_zone = NULL; - kfree (conf); + kfree(conf); mddev->private = NULL; return 0; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 98b0977..ff1dbec 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1427,10 +1427,8 @@ out_free_conf: if (conf) { if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); - if (conf->mirrors) - kfree(conf->mirrors); - if (conf->poolinfo) - kfree(conf->poolinfo); + kfree(conf->mirrors); + kfree(conf->poolinfo); kfree(conf); mddev->private = NULL; } @@ -1447,10 +1445,8 @@ static int stop(mddev_t *mddev) blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); - if (conf->mirrors) - kfree(conf->mirrors); - if (conf->poolinfo) - kfree(conf->poolinfo); + kfree(conf->mirrors); + kfree(conf->poolinfo); kfree(conf); mddev->private = NULL; return 0; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index fd7324a..62ebb1bc 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1737,8 +1737,7 @@ static int run(mddev_t *mddev) out_free_conf: if (conf->r10bio_pool) mempool_destroy(conf->r10bio_pool); - if (conf->mirrors) - kfree(conf->mirrors); + kfree(conf->mirrors); kfree(conf); mddev->private = NULL; out: @@ -1754,8 +1753,7 @@ static int stop(mddev_t *mddev) blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ if (conf->r10bio_pool) mempool_destroy(conf->r10bio_pool); - if (conf->mirrors) - kfree(conf->mirrors); + kfree(conf->mirrors); kfree(conf); mddev->private = NULL; return 0; -- cgit v0.10.2 From 718a538f945a84244a460df434c3f6f04701957b Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Sun, 17 Apr 2005 22:58:14 +0400 Subject: [PATCH] w1_therm: support for ds18b20, ds1822 thermal sensors. Support for ds18b20, ds1822 thermal sensors. Based on code from Tiziano M_ller . Patch is against 2.6.12-rc2 and should be applied without problems on top of any later kernels since w1_therm driver was not changed. Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 07fa494..2995c6c 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h @@ -27,8 +27,10 @@ #include #define W1_FAMILY_DEFAULT 0 -#define W1_FAMILY_THERM 0x10 #define W1_FAMILY_SMEM 0x01 +#define W1_THERM_DS18S20 0x10 +#define W1_THERM_DS1822 0x22 +#define W1_THERM_DS18B20 0x28 #define MAXNAMELEN 32 diff --git a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c index 70310f7..84e8043 100644 --- a/drivers/w1/w1_therm.c +++ b/drivers/w1/w1_therm.c @@ -53,6 +53,50 @@ static struct w1_family_ops w1_therm_fops = { .rvalname = "temp1_input", }; +static struct w1_family w1_therm_family_DS18S20 = { + .fid = W1_THERM_DS18S20, + .fops = &w1_therm_fops, +}; + +static struct w1_family w1_therm_family_DS18B20 = { + .fid = W1_THERM_DS18B20, + .fops = &w1_therm_fops, +}; +static struct w1_family w1_therm_family_DS1822 = { + .fid = W1_THERM_DS1822, + .fops = &w1_therm_fops, +}; + +struct w1_therm_family_converter +{ + u8 fid; + u8 broken; + u16 reserved; + struct w1_family *f; + int (*convert)(u8 rom[9]); +}; + +static inline int w1_DS18B20_convert_temp(u8 rom[9]); +static inline int w1_DS18S20_convert_temp(u8 rom[9]); + +static struct w1_therm_family_converter w1_therm_families[] = { + { + .fid = W1_THERM_DS18S20, + .f = &w1_therm_family_DS18S20, + .convert = w1_DS18S20_convert_temp + }, + { + .fid = W1_THERM_DS1822, + .f = &w1_therm_family_DS1822, + .convert = w1_DS18B20_convert_temp + }, + { + .fid = W1_THERM_DS18B20, + .f = &w1_therm_family_DS18B20, + .convert = w1_DS18B20_convert_temp + }, +}; + static ssize_t w1_therm_read_name(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_slave *sl = container_of(dev, struct w1_slave, dev); @@ -60,9 +104,19 @@ static ssize_t w1_therm_read_name(struct device *dev, struct device_attribute *a return sprintf(buf, "%s\n", sl->name); } -static inline int w1_convert_temp(u8 rom[9]) +static inline int w1_DS18B20_convert_temp(u8 rom[9]) +{ + int t = (rom[1] << 8) | rom[0]; + t /= 16; + return t; +} + +static inline int w1_DS18S20_convert_temp(u8 rom[9]) { int t, h; + + if (!rom[7]) + return 0; if (rom[1] == 0) t = ((s32)rom[0] >> 1)*1000; @@ -77,11 +131,22 @@ static inline int w1_convert_temp(u8 rom[9]) return t; } +static inline int w1_convert_temp(u8 rom[9], u8 fid) +{ + int i; + + for (i=0; irom)); + return sprintf(buf, "%d\n", w1_convert_temp(sl->rom, sl->family->fid)); } static int w1_therm_check_rom(u8 rom[9]) @@ -176,7 +241,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si for (i = 0; i < 9; ++i) count += sprintf(buf + count, "%02x ", sl->rom[i]); - count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom)); + count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid)); out: up(&dev->mutex); out_dec: @@ -186,19 +251,26 @@ out_dec: return count; } -static struct w1_family w1_therm_family = { - .fid = W1_FAMILY_THERM, - .fops = &w1_therm_fops, -}; - static int __init w1_therm_init(void) { - return w1_register_family(&w1_therm_family); + int err, i; + + for (i=0; i Date: Mon, 2 May 2005 14:26:42 +0400 Subject: [PATCH] w1_smem: support for new simple rom family [0x81 id]. Support for new simple rom family [0x81 id]. It is the same as existing 0x01 family, which is used in ds9490* w1 adapters. Patch is on top of new-thermal-sensor-families patch. Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 2995c6c..d01f042 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h @@ -27,7 +27,8 @@ #include #define W1_FAMILY_DEFAULT 0 -#define W1_FAMILY_SMEM 0x01 +#define W1_FAMILY_SMEM_01 0x01 +#define W1_FAMILY_SMEM_81 0x81 #define W1_THERM_DS18S20 0x10 #define W1_THERM_DS1822 0x22 #define W1_THERM_DS18B20 0x28 diff --git a/drivers/w1/w1_smem.c b/drivers/w1/w1_smem.c index 674eb75..4a335f1 100644 --- a/drivers/w1/w1_smem.c +++ b/drivers/w1/w1_smem.c @@ -99,19 +99,37 @@ out_dec: return count; } -static struct w1_family w1_smem_family = { - .fid = W1_FAMILY_SMEM, +static struct w1_family w1_smem_family_01 = { + .fid = W1_FAMILY_SMEM_01, + .fops = &w1_smem_fops, +}; + +static struct w1_family w1_smem_family_81 = { + .fid = W1_FAMILY_SMEM_81, .fops = &w1_smem_fops, }; static int __init w1_smem_init(void) { - return w1_register_family(&w1_smem_family); + int err; + + err = w1_register_family(&w1_smem_family_01); + if (err) + return err; + + err = w1_register_family(&w1_smem_family_81); + if (err) { + w1_unregister_family(&w1_smem_family_01); + return err; + } + + return 0; } static void __exit w1_smem_fini(void) { - w1_unregister_family(&w1_smem_family); + w1_unregister_family(&w1_smem_family_01); + w1_unregister_family(&w1_smem_family_81); } module_init(w1_smem_init); -- cgit v0.10.2 From 7785925dd8e0d2f389d4a9168f1683c6b249a552 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Fri, 20 May 2005 22:33:25 +0400 Subject: [PATCH] w1: cleanups. - white space changes. - list_for_each_entry/list_for_each_entry_safe and reverse changes. - small coding style changes. - removed redundant NULL checks. - use attribute group and macros instead of direct device attributes. Patch is havily based on work from Adrian Bunk and Dmitry Torokhov, thanks guys. Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index 2ab65c9..4f12079 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -3,9 +3,9 @@ menu "Dallas's 1-wire bus" config W1 tristate "Dallas's 1-wire support" ---help--- - Dallas's 1-wire bus is usefull to connect slow 1-pin devices + Dallas's 1-wire bus is usefull to connect slow 1-pin devices such as iButtons and thermal sensors. - + If you want W1 support, you should say Y here. This W1 support can also be built as a module. If so, the module @@ -17,8 +17,8 @@ config W1_MATROX help Say Y here if you want to communicate with your 1-wire devices using Matrox's G400 GPIO pins. - - This support is also available as a module. If so, the module + + This support is also available as a module. If so, the module will be called matrox_w1.ko. config W1_DS9490 @@ -27,17 +27,17 @@ config W1_DS9490 help Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge. - This support is also available as a module. If so, the module + This support is also available as a module. If so, the module will be called ds9490r.ko. -config W1_DS9490_BRIDGE +config W1_DS9490R_BRIDGE tristate "DS9490R USB <-> W1 transport layer for 1-wire" depends on W1_DS9490 help Say Y here if you want to communicate with your 1-wire devices using DS9490R USB bridge. - This support is also available as a module. If so, the module + This support is also available as a module. If so, the module will be called ds_w1_bridge.ko. config W1_THERM @@ -51,7 +51,7 @@ config W1_SMEM tristate "Simple 64bit memory family implementation" depends on W1 help - Say Y here if you want to connect 1-wire + Say Y here if you want to connect 1-wire simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire. endmenu diff --git a/drivers/w1/matrox_w1.c b/drivers/w1/matrox_w1.c index e565416..0b03f8f 100644 --- a/drivers/w1/matrox_w1.c +++ b/drivers/w1/matrox_w1.c @@ -1,8 +1,8 @@ /* - * matrox_w1.c + * matrox_w1.c * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -59,7 +59,7 @@ static struct pci_driver matrox_w1_pci_driver = { .remove = __devexit_p(matrox_w1_remove), }; -/* +/* * Matrox G400 DDC registers. */ @@ -177,8 +177,8 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi dev->bus_master = (struct w1_bus_master *)(dev + 1); - /* - * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c + /* + * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c */ dev->phys_addr = pci_resource_start(pdev, 1); diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 24a192e..5b49c9a 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -1,8 +1,8 @@ /* - * w1.c + * w1.c * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -99,6 +99,23 @@ static ssize_t w1_default_read_bin(struct kobject *kobj, char *buf, loff_t off, return sprintf(buf, "No family registered.\n"); } +static struct device_attribute w1_slave_attribute = + __ATTR(name, S_IRUGO, w1_default_read_name, NULL); + +static struct device_attribute w1_slave_attribute_val = + __ATTR(value, S_IRUGO, w1_default_read_name, NULL); + +static struct bin_attribute w1_slave_bin_attribute = { + .attr = { + .name = "w1_slave", + .mode = S_IRUGO, + .owner = THIS_MODULE, + }, + .size = W1_SLAVE_DATA_SIZE, + .read = &w1_default_read_bin, +}; + + static struct bus_type w1_bus_type = { .name = "w1", .match = w1_master_match, @@ -119,34 +136,16 @@ struct device w1_device = { .release = &w1_master_release }; -static struct device_attribute w1_slave_attribute = { - .attr = { - .name = "name", - .mode = S_IRUGO, - .owner = THIS_MODULE - }, - .show = &w1_default_read_name, -}; - -static struct device_attribute w1_slave_attribute_val = { - .attr = { - .name = "value", - .mode = S_IRUGO, - .owner = THIS_MODULE - }, - .show = &w1_default_read_name, -}; - static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_master *md = container_of (dev, struct w1_master, dev); ssize_t count; - + if (down_interruptible (&md->mutex)) return -EBUSY; count = sprintf(buf, "%s\n", md->name); - + up(&md->mutex); return count; @@ -156,12 +155,12 @@ static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct devic { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; - + if (down_interruptible(&md->mutex)) return -EBUSY; count = sprintf(buf, "0x%p\n", md->bus_master); - + up(&md->mutex); return count; } @@ -177,12 +176,12 @@ static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, stru { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; - + if (down_interruptible(&md->mutex)) return -EBUSY; count = sprintf(buf, "%d\n", md->max_slave_count); - + up(&md->mutex); return count; } @@ -191,12 +190,12 @@ static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct devi { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; - + if (down_interruptible(&md->mutex)) return -EBUSY; count = sprintf(buf, "%lu\n", md->attempts); - + up(&md->mutex); return count; } @@ -205,12 +204,12 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; - + if (down_interruptible(&md->mutex)) return -EBUSY; count = sprintf(buf, "%d\n", md->slave_count); - + up(&md->mutex); return count; } @@ -233,7 +232,7 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device list_for_each_safe(ent, n, &md->slist) { sl = list_entry(ent, struct w1_slave, w1_slave_entry); - c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name); + c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name); } } @@ -242,73 +241,44 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device return PAGE_SIZE - c; } -static struct device_attribute w1_master_attribute_slaves = { - .attr = { - .name = "w1_master_slaves", - .mode = S_IRUGO, - .owner = THIS_MODULE, - }, - .show = &w1_master_attribute_show_slaves, -}; -static struct device_attribute w1_master_attribute_slave_count = { - .attr = { - .name = "w1_master_slave_count", - .mode = S_IRUGO, - .owner = THIS_MODULE - }, - .show = &w1_master_attribute_show_slave_count, -}; -static struct device_attribute w1_master_attribute_attempts = { - .attr = { - .name = "w1_master_attempts", - .mode = S_IRUGO, - .owner = THIS_MODULE - }, - .show = &w1_master_attribute_show_attempts, -}; -static struct device_attribute w1_master_attribute_max_slave_count = { - .attr = { - .name = "w1_master_max_slave_count", - .mode = S_IRUGO, - .owner = THIS_MODULE - }, - .show = &w1_master_attribute_show_max_slave_count, -}; -static struct device_attribute w1_master_attribute_timeout = { - .attr = { - .name = "w1_master_timeout", - .mode = S_IRUGO, - .owner = THIS_MODULE - }, - .show = &w1_master_attribute_show_timeout, -}; -static struct device_attribute w1_master_attribute_pointer = { - .attr = { - .name = "w1_master_pointer", - .mode = S_IRUGO, - .owner = THIS_MODULE - }, - .show = &w1_master_attribute_show_pointer, -}; -static struct device_attribute w1_master_attribute_name = { - .attr = { - .name = "w1_master_name", - .mode = S_IRUGO, - .owner = THIS_MODULE - }, - .show = &w1_master_attribute_show_name, +#define W1_MASTER_ATTR_RO(_name, _mode) \ + struct device_attribute w1_master_attribute_##_name = \ + __ATTR(w1_master_##_name, _mode, \ + w1_master_attribute_show_##_name, NULL) + +static W1_MASTER_ATTR_RO(name, S_IRUGO); +static W1_MASTER_ATTR_RO(slaves, S_IRUGO); +static W1_MASTER_ATTR_RO(slave_count, S_IRUGO); +static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO); +static W1_MASTER_ATTR_RO(attempts, S_IRUGO); +static W1_MASTER_ATTR_RO(timeout, S_IRUGO); +static W1_MASTER_ATTR_RO(pointer, S_IRUGO); + +static struct attribute *w1_master_default_attrs[] = { + &w1_master_attribute_name.attr, + &w1_master_attribute_slaves.attr, + &w1_master_attribute_slave_count.attr, + &w1_master_attribute_max_slave_count.attr, + &w1_master_attribute_attempts.attr, + &w1_master_attribute_timeout.attr, + &w1_master_attribute_pointer.attr, + NULL }; -static struct bin_attribute w1_slave_bin_attribute = { - .attr = { - .name = "w1_slave", - .mode = S_IRUGO, - .owner = THIS_MODULE, - }, - .size = W1_SLAVE_DATA_SIZE, - .read = &w1_default_read_bin, +static struct attribute_group w1_master_defattr_group = { + .attrs = w1_master_default_attrs, }; +int w1_create_master_attributes(struct w1_master *master) +{ + return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group); +} + +void w1_destroy_master_attributes(struct w1_master *master) +{ + sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); +} + static int __w1_attach_slave_device(struct w1_slave *sl) { int err; @@ -341,7 +311,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl) memcpy(&sl->attr_bin, &w1_slave_bin_attribute, sizeof(sl->attr_bin)); memcpy(&sl->attr_name, &w1_slave_attribute, sizeof(sl->attr_name)); memcpy(&sl->attr_val, &w1_slave_attribute_val, sizeof(sl->attr_val)); - + sl->attr_bin.read = sl->family->fops->rbin; sl->attr_name.show = sl->family->fops->rname; sl->attr_val.show = sl->family->fops->rval; @@ -445,7 +415,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) static void w1_slave_detach(struct w1_slave *sl) { struct w1_netlink_msg msg; - + dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name); while (atomic_read(&sl->refcnt)) { @@ -471,8 +441,8 @@ static struct w1_master *w1_search_master(unsigned long data) { struct w1_master *dev; int found = 0; - - spin_lock_irq(&w1_mlock); + + spin_lock_bh(&w1_mlock); list_for_each_entry(dev, &w1_masters, w1_master_entry) { if (dev->bus_master->data == data) { found = 1; @@ -480,12 +450,12 @@ static struct w1_master *w1_search_master(unsigned long data) break; } } - spin_unlock_irq(&w1_mlock); + spin_unlock_bh(&w1_mlock); return (found)?dev:NULL; } -void w1_slave_found(unsigned long data, u64 rn) +static void w1_slave_found(unsigned long data, u64 rn) { int slave_count; struct w1_slave *sl; @@ -500,7 +470,7 @@ void w1_slave_found(unsigned long data, u64 rn) data); return; } - + tmp = (struct w1_reg_num *) &rn; slave_count = 0; @@ -513,8 +483,7 @@ void w1_slave_found(unsigned long data, u64 rn) sl->reg_num.crc == tmp->crc) { set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); break; - } - else if (sl->reg_num.family == tmp->family) { + } else if (sl->reg_num.family == tmp->family) { family_found = 1; break; } @@ -528,7 +497,7 @@ void w1_slave_found(unsigned long data, u64 rn) rn && ((le64_to_cpu(rn) >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) { w1_attach_slave_device(dev, tmp); } - + atomic_dec(&dev->refcnt); } @@ -545,8 +514,8 @@ void w1_search(struct w1_master *dev) desc_bit = 64; - while (!(id_bit && comp_bit) && !last_device - && count++ < dev->max_slave_count) { + while (!(id_bit && comp_bit) && !last_device && + count++ < dev->max_slave_count) { last = rn; rn = 0; @@ -591,8 +560,7 @@ void w1_search(struct w1_master *dev) last_family_desc = last_zero; } - } - else + } else search_bit = id_bit; tmp = search_bit; @@ -615,42 +583,15 @@ void w1_search(struct w1_master *dev) last_device = 1; desc_bit = last_zero; - + w1_slave_found(dev->bus_master->data, rn); } } -int w1_create_master_attributes(struct w1_master *dev) -{ - if ( device_create_file(&dev->dev, &w1_master_attribute_slaves) < 0 || - device_create_file(&dev->dev, &w1_master_attribute_slave_count) < 0 || - device_create_file(&dev->dev, &w1_master_attribute_attempts) < 0 || - device_create_file(&dev->dev, &w1_master_attribute_max_slave_count) < 0 || - device_create_file(&dev->dev, &w1_master_attribute_timeout) < 0|| - device_create_file(&dev->dev, &w1_master_attribute_pointer) < 0|| - device_create_file(&dev->dev, &w1_master_attribute_name) < 0) - return -EINVAL; - - return 0; -} - -void w1_destroy_master_attributes(struct w1_master *dev) -{ - device_remove_file(&dev->dev, &w1_master_attribute_slaves); - device_remove_file(&dev->dev, &w1_master_attribute_slave_count); - device_remove_file(&dev->dev, &w1_master_attribute_attempts); - device_remove_file(&dev->dev, &w1_master_attribute_max_slave_count); - device_remove_file(&dev->dev, &w1_master_attribute_timeout); - device_remove_file(&dev->dev, &w1_master_attribute_pointer); - device_remove_file(&dev->dev, &w1_master_attribute_name); -} - - -int w1_control(void *data) +static int w1_control(void *data) { - struct w1_slave *sl; - struct w1_master *dev; - struct list_head *ent, *ment, *n, *mn; + struct w1_slave *sl, *sln; + struct w1_master *dev, *n; int err, have_to_wait = 0; daemonize("w1_control"); @@ -665,9 +606,7 @@ int w1_control(void *data) if (signal_pending(current)) flush_signals(current); - list_for_each_safe(ment, mn, &w1_masters) { - dev = list_entry(ment, struct w1_master, w1_master_entry); - + list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry) { if (!control_needs_exit && !dev->need_exit) continue; /* @@ -679,9 +618,9 @@ int w1_control(void *data) continue; } - spin_lock(&w1_mlock); + spin_lock_bh(&w1_mlock); list_del(&dev->w1_master_entry); - spin_unlock(&w1_mlock); + spin_unlock_bh(&w1_mlock); if (control_needs_exit) { dev->need_exit = 1; @@ -695,19 +634,11 @@ int w1_control(void *data) wait_for_completion(&dev->dev_exited); - list_for_each_safe(ent, n, &dev->slist) { - sl = list_entry(ent, struct w1_slave, w1_slave_entry); - - if (!sl) - dev_warn(&dev->dev, - "%s: slave entry is NULL.\n", - __func__); - else { - list_del(&sl->w1_slave_entry); + list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { + list_del(&sl->w1_slave_entry); - w1_slave_detach(sl); - kfree(sl); - } + w1_slave_detach(sl); + kfree(sl); } w1_destroy_master_attributes(dev); atomic_dec(&dev->refcnt); @@ -720,8 +651,7 @@ int w1_control(void *data) int w1_process(void *data) { struct w1_master *dev = (struct w1_master *) data; - struct list_head *ent, *n; - struct w1_slave *sl; + struct w1_slave *sl, *sln; daemonize("%s", dev->name); allow_signal(SIGTERM); @@ -742,27 +672,20 @@ int w1_process(void *data) if (down_interruptible(&dev->mutex)) continue; - list_for_each_safe(ent, n, &dev->slist) { - sl = list_entry(ent, struct w1_slave, w1_slave_entry); - - if (sl) + list_for_each_entry(sl, &dev->slist, w1_slave_entry) clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); - } - - w1_search_devices(dev, w1_slave_found); - list_for_each_safe(ent, n, &dev->slist) { - sl = list_entry(ent, struct w1_slave, w1_slave_entry); + w1_search_devices(dev, w1_slave_found); - if (sl && !test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { + list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { + if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { list_del (&sl->w1_slave_entry); w1_slave_detach (sl); kfree (sl); dev->slave_count--; - } - else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) + } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) sl->ttl = dev->slave_ttl; } up(&dev->mutex); @@ -774,7 +697,7 @@ int w1_process(void *data) return 0; } -int w1_init(void) +static int w1_init(void) { int retval; @@ -814,18 +737,14 @@ err_out_exit_init: return retval; } -void w1_fini(void) +static void w1_fini(void) { struct w1_master *dev; - struct list_head *ent, *n; - list_for_each_safe(ent, n, &w1_masters) { - dev = list_entry(ent, struct w1_master, w1_master_entry); + list_for_each_entry(dev, &w1_masters, w1_master_entry) __w1_remove_master_device(dev); - } control_needs_exit = 1; - wait_for_completion(&w1_control_complete); driver_unregister(&w1_driver); diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index abbddaf..90a2e73 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h @@ -1,8 +1,8 @@ /* - * w1.h + * w1.h * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,9 +25,9 @@ struct w1_reg_num { #if defined(__LITTLE_ENDIAN_BITFIELD) - __u64 family:8, - id:48, - crc:8; + __u64 family:8, + id:48, + crc:8; #elif defined(__BIG_ENDIAN_BITFIELD) __u64 crc:8, id:48, @@ -74,11 +74,11 @@ struct w1_slave int ttl; struct w1_master *master; - struct w1_family *family; - struct device dev; - struct completion dev_released; + struct w1_family *family; + struct device dev; + struct completion dev_released; - struct bin_attribute attr_bin; + struct bin_attribute attr_bin; struct device_attribute attr_name, attr_val; }; @@ -90,16 +90,16 @@ struct w1_bus_master u8 (*read_bit)(unsigned long); void (*write_bit)(unsigned long, u8); - + u8 (*read_byte)(unsigned long); - void (*write_byte)(unsigned long, u8); - + void (*write_byte)(unsigned long, u8); + u8 (*read_block)(unsigned long, u8 *, int); void (*write_block)(unsigned long, u8 *, int); - - u8 (*touch_bit)(unsigned long, u8); - - u8 (*reset_bus)(unsigned long); + + u8 (*touch_bit)(unsigned long, u8); + + u8 (*reset_bus)(unsigned long); void (*search)(unsigned long, w1_slave_found_callback); }; @@ -123,21 +123,20 @@ struct w1_master int need_exit; pid_t kpid; - struct semaphore mutex; + struct semaphore mutex; struct device_driver *driver; - struct device dev; - struct completion dev_released; - struct completion dev_exited; + struct device dev; + struct completion dev_released; + struct completion dev_exited; struct w1_bus_master *bus_master; u32 seq, groups; - struct sock *nls; + struct sock *nls; }; int w1_create_master_attributes(struct w1_master *); -void w1_destroy_master_attributes(struct w1_master *); void w1_search(struct w1_master *dev); #endif /* __KERNEL__ */ diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index d1d56eca..3941fb0 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c @@ -1,8 +1,8 @@ /* - * w1_family.c + * w1_family.c * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index d01f042..218f127 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h @@ -1,8 +1,8 @@ /* - * w1_family.h + * w1_family.h * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,7 +39,7 @@ struct w1_family_ops { ssize_t (* rname)(struct device *, struct device_attribute *, char *); ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t); - + ssize_t (* rval)(struct device *, struct device_attribute *, char *); unsigned char rvalname[MAXNAMELEN]; }; @@ -48,9 +48,9 @@ struct w1_family { struct list_head family_entry; u8 fid; - + struct w1_family_ops *fops; - + atomic_t refcnt; u8 need_exit; }; diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 5f0bafb..ce24e3b 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c @@ -1,8 +1,8 @@ /* - * w1_int.c + * w1_int.c * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,8 +39,9 @@ extern spinlock_t w1_mlock; extern int w1_process(void *); -struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, - struct device_driver *driver, struct device *device) +static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, + struct device_driver *driver, + struct device *device) { struct w1_master *dev; int err; @@ -60,13 +61,13 @@ struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, dev->bus_master = (struct w1_bus_master *)(dev + 1); - dev->owner = THIS_MODULE; - dev->max_slave_count = slave_count; - dev->slave_count = 0; - dev->attempts = 0; - dev->kpid = -1; - dev->initialized = 0; - dev->id = id; + dev->owner = THIS_MODULE; + dev->max_slave_count = slave_count; + dev->slave_count = 0; + dev->attempts = 0; + dev->kpid = -1; + dev->initialized = 0; + dev->id = id; dev->slave_ttl = slave_ttl; atomic_set(&dev->refcnt, 2); @@ -105,7 +106,7 @@ struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, return dev; } -void w1_free_dev(struct w1_master *dev) +static void w1_free_dev(struct w1_master *dev) { device_unregister(&dev->dev); if (dev->nls && dev->nls->sk_socket) @@ -197,10 +198,8 @@ void __w1_remove_master_device(struct w1_master *dev) void w1_remove_master_device(struct w1_bus_master *bm) { struct w1_master *dev = NULL; - struct list_head *ent, *n; - list_for_each_safe(ent, n, &w1_masters) { - dev = list_entry(ent, struct w1_master, w1_master_entry); + list_for_each_entry(dev, &w1_masters, w1_master_entry) { if (!dev->initialized) continue; diff --git a/drivers/w1/w1_int.h b/drivers/w1/w1_int.h index fdb531e..4274082 100644 --- a/drivers/w1/w1_int.h +++ b/drivers/w1/w1_int.h @@ -1,8 +1,8 @@ /* - * w1_int.h + * w1_int.h * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,8 +27,6 @@ #include "w1.h" -struct w1_master * w1_alloc_dev(u32, int, int, struct device_driver *, struct device *); -void w1_free_dev(struct w1_master *dev); int w1_add_master_device(struct w1_bus_master *); void w1_remove_master_device(struct w1_bus_master *); void __w1_remove_master_device(struct w1_master *); diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 02796b5..298ee8b 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c @@ -1,8 +1,8 @@ /* - * w1_io.c + * w1_io.c * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h index 6c57300..327c22b 100644 --- a/drivers/w1/w1_io.h +++ b/drivers/w1/w1_io.h @@ -1,8 +1,8 @@ /* - * w1_io.h + * w1_io.h * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/w1/w1_log.h b/drivers/w1/w1_log.h index a6bf6f4..fe6bdf4 100644 --- a/drivers/w1/w1_log.h +++ b/drivers/w1/w1_log.h @@ -1,8 +1,8 @@ /* - * w1_log.h + * w1_log.h * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index ea1b530..8615756 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h @@ -33,13 +33,13 @@ enum w1_netlink_message_types { W1_MASTER_REMOVE, }; -struct w1_netlink_msg +struct w1_netlink_msg { __u8 type; __u8 reserved[3]; union { - struct w1_reg_num id; + struct w1_reg_num id; __u64 w1_id; struct { diff --git a/drivers/w1/w1_smem.c b/drivers/w1/w1_smem.c index 4a335f1..285eb8f 100644 --- a/drivers/w1/w1_smem.c +++ b/drivers/w1/w1_smem.c @@ -1,8 +1,8 @@ /* - * w1_smem.c + * w1_smem.c * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the smems of the GNU General Public License as published by @@ -70,7 +70,7 @@ static ssize_t w1_smem_read_val(struct device *dev, struct device_attribute *att static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj), - struct w1_slave, dev); + struct w1_slave, dev); int i; atomic_inc(&sl->refcnt); @@ -90,7 +90,7 @@ static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, siz for (i = 0; i < 8; ++i) count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]); count += sprintf(buf + count, "\n"); - + out: up(&sl->master->mutex); out_dec: diff --git a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c index 84e8043..e52abca 100644 --- a/drivers/w1/w1_therm.c +++ b/drivers/w1/w1_therm.c @@ -1,8 +1,8 @@ /* - * w1_therm.c + * w1_therm.c * * Copyright (c) 2004 Evgeniy Polyakov - * + * * * This program is free software; you can redistribute it and/or modify * it under the therms of the GNU General Public License as published by @@ -38,7 +38,7 @@ MODULE_AUTHOR("Evgeniy Polyakov "); MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family."); static u8 bad_roms[][9] = { - {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87}, + {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87}, {} }; @@ -163,7 +163,7 @@ static int w1_therm_check_rom(u8 rom[9]) static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj), - struct w1_slave, dev); + struct w1_slave, dev); struct w1_master *dev = sl->master; u8 rom[9], crc, verdict; int i, max_trying = 10; @@ -198,7 +198,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si unsigned int tm = 750; memcpy(&match[1], (u64 *) & sl->reg_num, 8); - + w1_write_block(dev, match, 9); w1_write_8(dev, W1_CONVERT_TEMP); @@ -211,7 +211,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si if (!w1_reset_bus (dev)) { w1_write_block(dev, match, 9); - + w1_write_8(dev, W1_READ_SCRATCHPAD); if ((count = w1_read_block(dev, rom, 9)) != 9) { dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count); -- cgit v0.10.2 From ca775c629a366ded01aae69da8410f70aaf85de1 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Fri, 20 May 2005 22:49:08 +0400 Subject: [PATCH] w1: new family structure. Removed some fields which are not required. First step for writing operations. Now only read and read name remain. Patch depends on w1 cleanups patch. Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 5b49c9a..c85d75e 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -102,9 +102,6 @@ static ssize_t w1_default_read_bin(struct kobject *kobj, char *buf, loff_t off, static struct device_attribute w1_slave_attribute = __ATTR(name, S_IRUGO, w1_default_read_name, NULL); -static struct device_attribute w1_slave_attribute_val = - __ATTR(value, S_IRUGO, w1_default_read_name, NULL); - static struct bin_attribute w1_slave_bin_attribute = { .attr = { .name = "w1_slave", @@ -310,12 +307,9 @@ static int __w1_attach_slave_device(struct w1_slave *sl) memcpy(&sl->attr_bin, &w1_slave_bin_attribute, sizeof(sl->attr_bin)); memcpy(&sl->attr_name, &w1_slave_attribute, sizeof(sl->attr_name)); - memcpy(&sl->attr_val, &w1_slave_attribute_val, sizeof(sl->attr_val)); sl->attr_bin.read = sl->family->fops->rbin; sl->attr_name.show = sl->family->fops->rname; - sl->attr_val.show = sl->family->fops->rval; - sl->attr_val.attr.name = sl->family->fops->rvalname; err = device_create_file(&sl->dev, &sl->attr_name); if (err < 0) { @@ -326,23 +320,12 @@ static int __w1_attach_slave_device(struct w1_slave *sl) return err; } - err = device_create_file(&sl->dev, &sl->attr_val); - if (err < 0) { - dev_err(&sl->dev, - "sysfs file creation for [%s] failed. err=%d\n", - sl->dev.bus_id, err); - device_remove_file(&sl->dev, &sl->attr_name); - device_unregister(&sl->dev); - return err; - } - err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin); if (err < 0) { dev_err(&sl->dev, "sysfs file creation for [%s] failed. err=%d\n", sl->dev.bus_id, err); device_remove_file(&sl->dev, &sl->attr_name); - device_remove_file(&sl->dev, &sl->attr_val); device_unregister(&sl->dev); return err; } @@ -428,7 +411,6 @@ static void w1_slave_detach(struct w1_slave *sl) sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin); device_remove_file(&sl->dev, &sl->attr_name); - device_remove_file(&sl->dev, &sl->attr_val); device_unregister(&sl->dev); w1_family_put(sl->family); diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 90a2e73..44dfb92 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h @@ -79,7 +79,7 @@ struct w1_slave struct completion dev_released; struct bin_attribute attr_bin; - struct device_attribute attr_name, attr_val; + struct device_attribute attr_name; }; typedef void (* w1_slave_found_callback)(unsigned long, u64); diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index 3941fb0..b8502d9 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c @@ -30,7 +30,7 @@ static LIST_HEAD(w1_families); static int w1_check_family(struct w1_family *f) { - if (!f->fops->rname || !f->fops->rbin || !f->fops->rval || !f->fops->rvalname) + if (!f->fops->rname || !f->fops->rbin) return -EINVAL; return 0; diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 218f127..b26da01 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h @@ -39,9 +39,6 @@ struct w1_family_ops { ssize_t (* rname)(struct device *, struct device_attribute *, char *); ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t); - - ssize_t (* rval)(struct device *, struct device_attribute *, char *); - unsigned char rvalname[MAXNAMELEN]; }; struct w1_family diff --git a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c index e52abca..b9896c1 100644 --- a/drivers/w1/w1_therm.c +++ b/drivers/w1/w1_therm.c @@ -43,14 +43,11 @@ static u8 bad_roms[][9] = { }; static ssize_t w1_therm_read_name(struct device *, struct device_attribute *attr, char *); -static ssize_t w1_therm_read_temp(struct device *, struct device_attribute *attr, char *); static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t); static struct w1_family_ops w1_therm_fops = { .rname = &w1_therm_read_name, .rbin = &w1_therm_read_bin, - .rval = &w1_therm_read_temp, - .rvalname = "temp1_input", }; static struct w1_family w1_therm_family_DS18S20 = { @@ -142,13 +139,6 @@ static inline int w1_convert_temp(u8 rom[9], u8 fid) return 0; } -static ssize_t w1_therm_read_temp(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w1_slave *sl = container_of(dev, struct w1_slave, dev); - - return sprintf(buf, "%d\n", w1_convert_temp(sl->rom, sl->family->fid)); -} - static int w1_therm_check_rom(u8 rom[9]) { int i; -- cgit v0.10.2 From c7b2b2a723174d22a743180d5367f0028226031b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 21 Jun 2005 21:01:59 -0700 Subject: [PATCH] w1: fix build issues Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/w1_smem.c b/drivers/w1/w1_smem.c index 285eb8f..70d2d46 100644 --- a/drivers/w1/w1_smem.c +++ b/drivers/w1/w1_smem.c @@ -37,14 +37,11 @@ MODULE_AUTHOR("Evgeniy Polyakov "); MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family."); static ssize_t w1_smem_read_name(struct device *, struct device_attribute *attr, char *); -static ssize_t w1_smem_read_val(struct device *, struct device_attribute *attr, char *); static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t); static struct w1_family_ops w1_smem_fops = { .rname = &w1_smem_read_name, .rbin = &w1_smem_read_bin, - .rval = &w1_smem_read_val, - .rvalname = "id", }; static ssize_t w1_smem_read_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -54,19 +51,6 @@ static ssize_t w1_smem_read_name(struct device *dev, struct device_attribute *at return sprintf(buf, "%s\n", sl->name); } -static ssize_t w1_smem_read_val(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w1_slave *sl = container_of(dev, struct w1_slave, dev); - int i; - ssize_t count = 0; - - for (i = 0; i < 8; ++i) - count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]); - count += sprintf(buf + count, "\n"); - - return count; -} - static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj), -- cgit v0.10.2 From 4e470aa9642d49230bcdfbb393cf5a81da333aba Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Fri, 20 May 2005 22:50:33 +0400 Subject: [PATCH] w1_therm: removed duplicated family id. We can access family id through w1_family structure. Signed-off-by: Evgeniy Polyakov diff --git a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c index b9896c1..165526c 100644 --- a/drivers/w1/w1_therm.c +++ b/drivers/w1/w1_therm.c @@ -66,7 +66,6 @@ static struct w1_family w1_therm_family_DS1822 = { struct w1_therm_family_converter { - u8 fid; u8 broken; u16 reserved; struct w1_family *f; @@ -78,17 +77,14 @@ static inline int w1_DS18S20_convert_temp(u8 rom[9]); static struct w1_therm_family_converter w1_therm_families[] = { { - .fid = W1_THERM_DS18S20, .f = &w1_therm_family_DS18S20, .convert = w1_DS18S20_convert_temp }, { - .fid = W1_THERM_DS1822, .f = &w1_therm_family_DS1822, .convert = w1_DS18B20_convert_temp }, { - .fid = W1_THERM_DS18B20, .f = &w1_therm_family_DS18B20, .convert = w1_DS18B20_convert_temp }, @@ -133,7 +129,7 @@ static inline int w1_convert_temp(u8 rom[9], u8 fid) int i; for (i=0; ifid == fid) return w1_therm_families[i].convert(rom); return 0; -- cgit v0.10.2 From be57ce267fd558c52d2389530c15618681b7cfa7 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Sat, 4 Jun 2005 01:21:46 +0400 Subject: [PATCH] w1: Cleans up usage of touch_bit/w1_read_bit/w1_write_bit. Cleans up usage of touch_bit/w1_read_bit/w1_write_bit. Signed-off-by: Ben Gardner Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index ce24e3b..280f140 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c @@ -121,6 +121,14 @@ int w1_add_master_device(struct w1_bus_master *master) int retval = 0; struct w1_netlink_msg msg; + /* validate minimum functionality */ + if (!(master->touch_bit && master->reset_bus) && + !(master->write_bit && master->read_bit)) + { + printk(KERN_ERR "w1_add_master_device: invalid function set\n"); + return(-EINVAL); + } + dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device); if (!dev) return -ENOMEM; diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 298ee8b..2173336 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c @@ -55,15 +55,29 @@ void w1_delay(unsigned long tm) udelay(tm * w1_delay_parm); } +static void w1_write_bit(struct w1_master *dev, int bit); +static u8 w1_read_bit(struct w1_master *dev); + +/** + * Generates a write-0 or write-1 cycle and samples the level. + */ u8 w1_touch_bit(struct w1_master *dev, int bit) { if (dev->bus_master->touch_bit) return dev->bus_master->touch_bit(dev->bus_master->data, bit); - else + else if (bit) return w1_read_bit(dev); + else { + w1_write_bit(dev, 0); + return(0); + } } -void w1_write_bit(struct w1_master *dev, int bit) +/** + * Generates a write-0 or write-1 cycle. + * Only call if dev->bus_master->touch_bit is NULL + */ +static void w1_write_bit(struct w1_master *dev, int bit) { if (bit) { dev->bus_master->write_bit(dev->bus_master->data, 0); @@ -78,6 +92,12 @@ void w1_write_bit(struct w1_master *dev, int bit) } } +/** + * Writes 8 bits. + * + * @param dev the master device + * @param byte the byte to write + */ void w1_write_8(struct w1_master *dev, u8 byte) { int i; @@ -86,10 +106,15 @@ void w1_write_8(struct w1_master *dev, u8 byte) dev->bus_master->write_byte(dev->bus_master->data, byte); else for (i = 0; i < 8; ++i) - w1_write_bit(dev, (byte >> i) & 0x1); + w1_touch_bit(dev, (byte >> i) & 0x1); } -u8 w1_read_bit(struct w1_master *dev) + +/** + * Generates a write-1 cycle and samples the level. + * Only call if dev->bus_master->touch_bit is NULL + */ +static u8 w1_read_bit(struct w1_master *dev) { int result; @@ -104,6 +129,12 @@ u8 w1_read_bit(struct w1_master *dev) return result & 0x1; } +/** + * Reads 8 bits. + * + * @param dev the master device + * @return the byte read + */ u8 w1_read_8(struct w1_master * dev) { int i; @@ -113,12 +144,20 @@ u8 w1_read_8(struct w1_master * dev) res = dev->bus_master->read_byte(dev->bus_master->data); else for (i = 0; i < 8; ++i) - res |= (w1_read_bit(dev) << i); + res |= (w1_touch_bit(dev,1) << i); return res; } -void w1_write_block(struct w1_master *dev, u8 *buf, int len) +/** + * Writes a series of bytes. + * + * @param dev the master device + * @param buf pointer to the data to write + * @param len the number of bytes to write + * @return the byte read + */ +void w1_write_block(struct w1_master *dev, const u8 *buf, int len) { int i; @@ -129,6 +168,14 @@ void w1_write_block(struct w1_master *dev, u8 *buf, int len) w1_write_8(dev, buf[i]); } +/** + * Reads a series of bytes. + * + * @param dev the master device + * @param buf pointer to the buffer to fill + * @param len the number of bytes to read + * @return the number of bytes read + */ u8 w1_read_block(struct w1_master *dev, u8 *buf, int len) { int i; @@ -145,9 +192,15 @@ u8 w1_read_block(struct w1_master *dev, u8 *buf, int len) return ret; } +/** + * Issues a reset bus sequence. + * + * @param dev The bus master pointer + * @return 0=Device present, 1=No device present or error + */ int w1_reset_bus(struct w1_master *dev) { - int result = 0; + int result; if (dev->bus_master->reset_bus) result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1; @@ -183,9 +236,8 @@ void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb) w1_search(dev); } -EXPORT_SYMBOL(w1_write_bit); +EXPORT_SYMBOL(w1_touch_bit); EXPORT_SYMBOL(w1_write_8); -EXPORT_SYMBOL(w1_read_bit); EXPORT_SYMBOL(w1_read_8); EXPORT_SYMBOL(w1_reset_bus); EXPORT_SYMBOL(w1_calc_crc8); diff --git a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h index 327c22b..d6daa31 100644 --- a/drivers/w1/w1_io.h +++ b/drivers/w1/w1_io.h @@ -26,13 +26,11 @@ void w1_delay(unsigned long); u8 w1_touch_bit(struct w1_master *, int); -void w1_write_bit(struct w1_master *, int); void w1_write_8(struct w1_master *, u8); -u8 w1_read_bit(struct w1_master *); u8 w1_read_8(struct w1_master *); int w1_reset_bus(struct w1_master *); u8 w1_calc_crc8(u8 *, int); -void w1_write_block(struct w1_master *, u8 *, int); +void w1_write_block(struct w1_master *, const u8 *, int); u8 w1_read_block(struct w1_master *, u8 *, int); void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb); -- cgit v0.10.2 From 6b729861831177b270a2932a13e79cb41d673146 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Sat, 4 Jun 2005 01:30:43 +0400 Subject: [PATCH] w1: Added the triplet w1 master method and changes w1_search() to use it. Adds the triplet w1 master method and changes w1_search() to use it. Signed-off-by: Ben Gardner Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index c85d75e..4fa959f 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -135,7 +135,7 @@ struct device w1_device = { static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) { - struct w1_master *md = container_of (dev, struct w1_master, dev); + struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; if (down_interruptible (&md->mutex)) @@ -212,7 +212,6 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d } static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf) - { struct w1_master *md = container_of(dev, struct w1_master, dev); int c = PAGE_SIZE; @@ -286,13 +285,13 @@ static int __w1_attach_slave_device(struct w1_slave *sl) sl->dev.release = &w1_slave_release; snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id), - "%02x-%012llx", - (unsigned int) sl->reg_num.family, - (unsigned long long) sl->reg_num.id); - snprintf (&sl->name[0], sizeof(sl->name), - "%02x-%012llx", - (unsigned int) sl->reg_num.family, - (unsigned long long) sl->reg_num.id); + "%02x-%012llx", + (unsigned int) sl->reg_num.family, + (unsigned long long) sl->reg_num.id); + snprintf(&sl->name[0], sizeof(sl->name), + "%02x-%012llx", + (unsigned int) sl->reg_num.family, + (unsigned long long) sl->reg_num.id); dev_dbg(&sl->dev, "%s: registering %s.\n", __func__, &sl->dev.bus_id[0]); @@ -300,8 +299,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) err = device_register(&sl->dev); if (err < 0) { dev_err(&sl->dev, - "Device registration [%s] failed. err=%d\n", - sl->dev.bus_id, err); + "Device registration [%s] failed. err=%d\n", + sl->dev.bus_id, err); return err; } @@ -314,8 +313,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) err = device_create_file(&sl->dev, &sl->attr_name); if (err < 0) { dev_err(&sl->dev, - "sysfs file creation for [%s] failed. err=%d\n", - sl->dev.bus_id, err); + "sysfs file creation for [%s] failed. err=%d\n", + sl->dev.bus_id, err); device_unregister(&sl->dev); return err; } @@ -323,8 +322,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin); if (err < 0) { dev_err(&sl->dev, - "sysfs file creation for [%s] failed. err=%d\n", - sl->dev.bus_id, err); + "sysfs file creation for [%s] failed. err=%d\n", + sl->dev.bus_id, err); device_remove_file(&sl->dev, &sl->attr_name); device_unregister(&sl->dev); return err; @@ -483,26 +482,39 @@ static void w1_slave_found(unsigned long data, u64 rn) atomic_dec(&dev->refcnt); } -void w1_search(struct w1_master *dev) +/** + * Performs a ROM Search & registers any devices found. + * The 1-wire search is a simple binary tree search. + * For each bit of the address, we read two bits and write one bit. + * The bit written will put to sleep all devies that don't match that bit. + * When the two reads differ, the direction choice is obvious. + * When both bits are 0, we must choose a path to take. + * When we can scan all 64 bits without having to choose a path, we are done. + * + * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com + * + * @dev The master device to search + * @cb Function to call when a device is found + */ +void w1_search(struct w1_master *dev, w1_slave_found_callback cb) { - u64 last, rn, tmp; - int i, count = 0; - int last_family_desc, last_zero, last_device; - int search_bit, id_bit, comp_bit, desc_bit; + u64 last_rn, rn, tmp64; + int i, slave_count = 0; + int last_zero, last_device; + int search_bit, desc_bit; + u8 triplet_ret = 0; - search_bit = id_bit = comp_bit = 0; - rn = tmp = last = 0; - last_device = last_zero = last_family_desc = 0; + search_bit = 0; + rn = last_rn = 0; + last_device = 0; + last_zero = -1; desc_bit = 64; - while (!(id_bit && comp_bit) && !last_device && - count++ < dev->max_slave_count) { - last = rn; + while ( !last_device && (slave_count++ < dev->max_slave_count) ) { + last_rn = rn; rn = 0; - last_family_desc = 0; - /* * Reset bus and all 1-wire device state machines * so they can respond to our requests. @@ -514,59 +526,39 @@ void w1_search(struct w1_master *dev) break; } -#if 1 + /* Start the search */ w1_write_8(dev, W1_SEARCH); for (i = 0; i < 64; ++i) { - /* - * Read 2 bits from bus. - * All who don't sleep must send ID bit and COMPLEMENT ID bit. - * They actually are ANDed between all senders. - */ - id_bit = w1_touch_bit(dev, 1); - comp_bit = w1_touch_bit(dev, 1); - - if (id_bit && comp_bit) - break; - - if (id_bit == 0 && comp_bit == 0) { - if (i == desc_bit) - search_bit = 1; - else if (i > desc_bit) - search_bit = 0; - else - search_bit = ((last >> i) & 0x1); - - if (search_bit == 0) { - last_zero = i; - if (last_zero < 9) - last_family_desc = last_zero; - } + /* Determine the direction/search bit */ + if (i == desc_bit) + search_bit = 1; /* took the 0 path last time, so take the 1 path */ + else if (i > desc_bit) + search_bit = 0; /* take the 0 path on the next branch */ + else + search_bit = ((last_rn >> i) & 0x1); - } else - search_bit = id_bit; + /** Read two bits and write one bit */ + triplet_ret = w1_triplet(dev, search_bit); - tmp = search_bit; - rn |= (tmp << i); + /* quit if no device responded */ + if ( (triplet_ret & 0x03) == 0x03 ) + break; - /* - * Write 1 bit to bus - * and make all who don't have "search_bit" in "i"'th position - * in it's registration number sleep. - */ - if (dev->bus_master->touch_bit) - w1_touch_bit(dev, search_bit); - else - w1_write_bit(dev, search_bit); + /* If both directions were valid, and we took the 0 path... */ + if (triplet_ret == 0) + last_zero = i; + /* extract the direction taken & update the device number */ + tmp64 = (triplet_ret >> 2); + rn |= (tmp64 << i); } -#endif - - if (desc_bit == last_zero) - last_device = 1; - desc_bit = last_zero; - - w1_slave_found(dev->bus_master->data, rn); + if ( (triplet_ret & 0x03) != 0x03 ) { + if ( (desc_bit == last_zero) || (last_zero < 0)) + last_device = 1; + desc_bit = last_zero; + cb(dev->bus_master->data, rn); + } } } diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 44dfb92..3cfdd08 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h @@ -25,9 +25,9 @@ struct w1_reg_num { #if defined(__LITTLE_ENDIAN_BITFIELD) - __u64 family:8, - id:48, - crc:8; + __u64 family:8, + id:48, + crc:8; #elif defined(__BIG_ENDIAN_BITFIELD) __u64 crc:8, id:48, @@ -84,24 +84,71 @@ struct w1_slave typedef void (* w1_slave_found_callback)(unsigned long, u64); + +/** + * Note: read_bit and write_bit are very low level functions and should only + * be used with hardware that doesn't really support 1-wire operations, + * like a parallel/serial port. + * Either define read_bit and write_bit OR define, at minimum, touch_bit and + * reset_bus. + */ struct w1_bus_master { - unsigned long data; - - u8 (*read_bit)(unsigned long); - void (*write_bit)(unsigned long, u8); - - u8 (*read_byte)(unsigned long); - void (*write_byte)(unsigned long, u8); - - u8 (*read_block)(unsigned long, u8 *, int); - void (*write_block)(unsigned long, u8 *, int); - - u8 (*touch_bit)(unsigned long, u8); - - u8 (*reset_bus)(unsigned long); - - void (*search)(unsigned long, w1_slave_found_callback); + /** the first parameter in all the functions below */ + unsigned long data; + + /** + * Sample the line level + * @return the level read (0 or 1) + */ + u8 (*read_bit)(unsigned long); + + /** Sets the line level */ + void (*write_bit)(unsigned long, u8); + + /** + * touch_bit is the lowest-level function for devices that really + * support the 1-wire protocol. + * touch_bit(0) = write-0 cycle + * touch_bit(1) = write-1 / read cycle + * @return the bit read (0 or 1) + */ + u8 (*touch_bit)(unsigned long, u8); + + /** + * Reads a bytes. Same as 8 touch_bit(1) calls. + * @return the byte read + */ + u8 (*read_byte)(unsigned long); + + /** + * Writes a byte. Same as 8 touch_bit(x) calls. + */ + void (*write_byte)(unsigned long, u8); + + /** + * Same as a series of read_byte() calls + * @return the number of bytes read + */ + u8 (*read_block)(unsigned long, u8 *, int); + + /** Same as a series of write_byte() calls */ + void (*write_block)(unsigned long, const u8 *, int); + + /** + * Combines two reads and a smart write for ROM searches + * @return bit0=Id bit1=comp_id bit2=dir_taken + */ + u8 (*triplet)(unsigned long, u8); + + /** + * long write-0 with a read for the presence pulse detection + * @return -1=Error, 0=Device present, 1=No device present + */ + u8 (*reset_bus)(unsigned long); + + /** Really nice hardware can handles the ROM searches */ + void (*search)(unsigned long, w1_slave_found_callback); }; struct w1_master @@ -137,7 +184,7 @@ struct w1_master }; int w1_create_master_attributes(struct w1_master *); -void w1_search(struct w1_master *dev); +void w1_search(struct w1_master *dev, w1_slave_found_callback cb); #endif /* __KERNEL__ */ diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 2173336..00f0322 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c @@ -130,6 +130,47 @@ static u8 w1_read_bit(struct w1_master *dev) } /** + * Does a triplet - used for searching ROM addresses. + * Return bits: + * bit 0 = id_bit + * bit 1 = comp_bit + * bit 2 = dir_taken + * If both bits 0 & 1 are set, the search should be restarted. + * + * @param dev the master device + * @param bdir the bit to write if both id_bit and comp_bit are 0 + * @return bit fields - see above + */ +u8 w1_triplet(struct w1_master *dev, int bdir) +{ + if ( dev->bus_master->triplet ) + return(dev->bus_master->triplet(dev->bus_master->data, bdir)); + else { + u8 id_bit = w1_touch_bit(dev, 1); + u8 comp_bit = w1_touch_bit(dev, 1); + u8 retval; + + if ( id_bit && comp_bit ) + return(0x03); /* error */ + + if ( !id_bit && !comp_bit ) { + /* Both bits are valid, take the direction given */ + retval = bdir ? 0x04 : 0; + } else { + /* Only one bit is valid, take that direction */ + bdir = id_bit; + retval = id_bit ? 0x05 : 0x02; + } + + if ( dev->bus_master->touch_bit ) + w1_touch_bit(dev, bdir); + else + w1_write_bit(dev, bdir); + return(retval); + } +} + +/** * Reads 8 bits. * * @param dev the master device @@ -233,7 +274,7 @@ void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb) if (dev->bus_master->search) dev->bus_master->search(dev->bus_master->data, cb); else - w1_search(dev); + w1_search(dev, cb); } EXPORT_SYMBOL(w1_touch_bit); diff --git a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h index d6daa31..af58297 100644 --- a/drivers/w1/w1_io.h +++ b/drivers/w1/w1_io.h @@ -26,6 +26,7 @@ void w1_delay(unsigned long); u8 w1_touch_bit(struct w1_master *, int); +u8 w1_triplet(struct w1_master *dev, int bdir); void w1_write_8(struct w1_master *, u8); u8 w1_read_8(struct w1_master *); int w1_reset_bus(struct w1_master *); -- cgit v0.10.2 From 2a9d0c178158da4a9bcf22311a414c26a8102d13 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Sat, 4 Jun 2005 01:31:02 +0400 Subject: [PATCH] w1: Adds a sysfs entry (w1_master_search) that allows you to disable/enable periodic searches. Adds a sysfs entry (w1_master_search) that allows you to disable/enable periodic searches. Signed-off-by: Ben Gardner Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 4fa959f..48da175 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -148,6 +148,39 @@ static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_a return count; } +static ssize_t w1_master_attribute_store_search(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ + struct w1_master *md = container_of(dev, struct w1_master, dev); + + if (down_interruptible (&md->mutex)) + return -EBUSY; + + md->search_count = simple_strtol(buf, NULL, 0); + + up(&md->mutex); + + return count; +} + +static ssize_t w1_master_attribute_show_search(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct w1_master *md = container_of(dev, struct w1_master, dev); + ssize_t count; + + if (down_interruptible (&md->mutex)) + return -EBUSY; + + count = sprintf(buf, "%d\n", md->search_count); + + up(&md->mutex); + + return count; +} + static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); @@ -242,6 +275,12 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device __ATTR(w1_master_##_name, _mode, \ w1_master_attribute_show_##_name, NULL) +#define W1_MASTER_ATTR_RW(_name, _mode) \ + struct device_attribute w1_master_attribute_##_name = \ + __ATTR(w1_master_##_name, _mode, \ + w1_master_attribute_show_##_name, \ + w1_master_attribute_store_##_name) + static W1_MASTER_ATTR_RO(name, S_IRUGO); static W1_MASTER_ATTR_RO(slaves, S_IRUGO); static W1_MASTER_ATTR_RO(slave_count, S_IRUGO); @@ -249,6 +288,7 @@ static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO); static W1_MASTER_ATTR_RO(attempts, S_IRUGO); static W1_MASTER_ATTR_RO(timeout, S_IRUGO); static W1_MASTER_ATTR_RO(pointer, S_IRUGO); +static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO); static struct attribute *w1_master_default_attrs[] = { &w1_master_attribute_name.attr, @@ -258,6 +298,7 @@ static struct attribute *w1_master_default_attrs[] = { &w1_master_attribute_attempts.attr, &w1_master_attribute_timeout.attr, &w1_master_attribute_pointer.attr, + &w1_master_attribute_search.attr, NULL }; @@ -643,11 +684,14 @@ int w1_process(void *data) if (!dev->initialized) continue; + if (dev->search_count == 0) + continue; + if (down_interruptible(&dev->mutex)) continue; list_for_each_entry(sl, &dev->slist, w1_slave_entry) - clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); + clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); w1_search_devices(dev, w1_slave_found); @@ -662,6 +706,10 @@ int w1_process(void *data) } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) sl->ttl = dev->slave_ttl; } + + if (dev->search_count > 0) + dev->search_count--; + up(&dev->mutex); } diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 3cfdd08..6b5f7be 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h @@ -162,6 +162,7 @@ struct w1_master int slave_ttl; int initialized; u32 id; + int search_count; atomic_t refcnt; diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 280f140..cf18f13 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c @@ -69,6 +69,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, dev->initialized = 0; dev->id = id; dev->slave_ttl = slave_ttl; + dev->search_count = -1; /* continual scan */ atomic_set(&dev->refcnt, 2); -- cgit v0.10.2 From 99c5bfe993af1af37ddd615e72207dc7220dc526 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Sat, 4 Jun 2005 01:31:26 +0400 Subject: [PATCH] w1: Adds a default family so that new slave families will show up in sysfs. Adds a default family so that new slave families will show up in sysfs. Signed-off-by: Ben Gardner Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 48da175..0e6ccd4 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -59,6 +59,19 @@ static pid_t control_thread; static int control_needs_exit; static DECLARE_COMPLETION(w1_control_complete); +/* stuff for the default family */ +static ssize_t w1_famdefault_read_name(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w1_slave *sl = container_of(dev, struct w1_slave, dev); + return(sprintf(buf, "%s\n", sl->name)); +} +static struct w1_family_ops w1_default_fops = { + .rname = &w1_famdefault_read_name, +}; +static struct w1_family w1_default_family = { + .fops = &w1_default_fops, +}; + static int w1_master_match(struct device *dev, struct device_driver *drv) { return 1; @@ -360,14 +373,16 @@ static int __w1_attach_slave_device(struct w1_slave *sl) return err; } - err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin); - if (err < 0) { - dev_err(&sl->dev, - "sysfs file creation for [%s] failed. err=%d\n", - sl->dev.bus_id, err); - device_remove_file(&sl->dev, &sl->attr_name); - device_unregister(&sl->dev); - return err; + if ( sl->attr_bin.read ) { + err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin); + if (err < 0) { + dev_err(&sl->dev, + "sysfs file creation for [%s] failed. err=%d\n", + sl->dev.bus_id, err); + device_remove_file(&sl->dev, &sl->attr_name); + device_unregister(&sl->dev); + return err; + } } list_add_tail(&sl->w1_slave_entry, &sl->master->slist); @@ -403,12 +418,10 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) spin_lock(&w1_flock); f = w1_family_registered(rn->family); if (!f) { - spin_unlock(&w1_flock); + f= &w1_default_family; dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n", rn->family, rn->family, (unsigned long long)rn->id, rn->crc); - kfree(sl); - return -ENODEV; } __w1_family_get(f); spin_unlock(&w1_flock); @@ -449,7 +462,9 @@ static void w1_slave_detach(struct w1_slave *sl) flush_signals(current); } - sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin); + if ( sl->attr_bin.read ) { + sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin); + } device_remove_file(&sl->dev, &sl->attr_name); device_unregister(&sl->dev); w1_family_put(sl->family); -- cgit v0.10.2 From 4754639d88e922af451b399af09ac1bb442c35e5 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Sat, 4 Jun 2005 01:31:47 +0400 Subject: [PATCH] w1: Updates the w1 documentation (w1.generic) Updates the w1 documentation (w1.generic) Signed-off-by: Ben Gardner Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/w1/w1.generic b/Documentation/w1/w1.generic index eace304..f937fbe 100644 --- a/Documentation/w1/w1.generic +++ b/Documentation/w1/w1.generic @@ -1,19 +1,92 @@ -Any w1 device must be connected to w1 bus master device - for example -ds9490 usb device or w1-over-GPIO or RS232 converter. -Driver for w1 bus master must provide several functions(you can find -them in struct w1_bus_master definition in w1.h) which then will be -called by w1 core to send various commands over w1 bus(by default it is -reset and search commands). When some device is found on the bus, w1 core -checks if driver for it's family is loaded. -If driver is loaded w1 core creates new w1_slave object and registers it -in the system(creates some generic sysfs files(struct w1_family_ops in -w1_family.h), notifies any registered listener and so on...). -It is device driver's business to provide any communication method -upstream. -For example w1_therm driver(ds18?20 thermal sensor family driver) -provides temperature reading function which is bound to ->rbin() method -of the above w1_family_ops structure. -w1_smem - driver for simple 64bit memory cell provides ID reading -method. +The 1-wire (w1) subsystem +------------------------------------------------------------------ +The 1-wire bus is a simple master-slave bus that communicates via a single +signal wire (plus ground, so two wires). + +Devices communicate on the bus by pulling the signal to ground via an open +drain output and by sampling the logic level of the signal line. + +The w1 subsystem provides the framework for managing w1 masters and +communication with slaves. + +All w1 slave devices must be connected to a w1 bus master device. + +Example w1 master devices: + DS9490 usb device + W1-over-GPIO + DS2482 (i2c to w1 bridge) + Emulated devices, such as a RS232 converter, parallel port adapter, etc + + +What does the w1 subsystem do? +------------------------------------------------------------------ +When a w1 master driver registers with the w1 subsystem, the following occurs: + + - sysfs entries for that w1 master are created + - the w1 bus is periodically searched for new slave devices + +When a device is found on the bus, w1 core checks if driver for it's family is +loaded. If so, the family driver is attached to the slave. +If there is no driver for the family, a simple sysfs entry is created +for the slave device. + + +W1 device families +------------------------------------------------------------------ +Slave devices are handled by a driver written for a family of w1 devices. + +A family driver populates a struct w1_family_ops (see w1_family.h) and +registers with the w1 subsystem. + +Current family drivers: +w1_therm - (ds18?20 thermal sensor family driver) + provides temperature reading function which is bound to ->rbin() method + of the above w1_family_ops structure. + +w1_smem - driver for simple 64bit memory cell provides ID reading method. You can call above methods by reading appropriate sysfs files. + + +What does a w1 master driver need to implement? +------------------------------------------------------------------ + +The driver for w1 bus master must provide at minimum two functions. + +Emulated devices must provide the ability to set the output signal level +(write_bit) and sample the signal level (read_bit). + +Devices that support the 1-wire natively must provide the ability to write and +sample a bit (touch_bit) and reset the bus (reset_bus). + +Most hardware provides higher-level functions that offload w1 handling. +See struct w1_bus_master definition in w1.h for details. + + +w1 master sysfs interface +------------------------------------------------------------------ + - a directory for a found device. The format is family-serial +bus - (standard) symlink to the w1 bus +driver - (standard) symlink to the w1 driver +w1_master_attempts - the number of times a search was attempted +w1_master_max_slave_count + - the maximum slaves that may be attached to a master +w1_master_name - the name of the device (w1_bus_masterX) +w1_master_search - the number of searches left to do, -1=continual (default) +w1_master_slave_count + - the number of slaves found +w1_master_slaves - the names of the slaves, one per line +w1_master_timeout - the delay in seconds between searches + +If you have a w1 bus that never changes (you don't add or remove devices), +you can set w1_master_search to a positive value to disable searches. + + +w1 slave sysfs interface +------------------------------------------------------------------ +bus - (standard) symlink to the w1 bus +driver - (standard) symlink to the w1 driver +name - the device name, usually the same as the directory name +w1_slave - (optional) a binary file whose meaning depends on the + family driver + -- cgit v0.10.2 From 6adf87bd7b7832105b9c6bc08adf6a4d229f1e79 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Sat, 4 Jun 2005 01:29:25 +0400 Subject: [PATCH] w1: reconnect feature. I've created reconnect feature - if on start there are no registered families all new devices will have defailt family, later when driver for appropriate family is loaded, slaves, which were faound earlier, will still have defult family instead of right one. Reconnect feature will force control thread to run through all master devices and all slaves found and search for slaves with default family id and try to reconnect them. It does not store newly registered family and does not check only those slaves which have reg_num.family the same as being registered one - all slaves with default family are reconnected. Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/ds_w1_bridge.c b/drivers/w1/ds_w1_bridge.c index 0baaeb5..7bddd8a 100644 --- a/drivers/w1/ds_w1_bridge.c +++ b/drivers/w1/ds_w1_bridge.c @@ -83,11 +83,11 @@ static u8 ds9490r_read_byte(unsigned long data) return byte; } -static void ds9490r_write_block(unsigned long data, u8 *buf, int len) +static void ds9490r_write_block(unsigned long data, const u8 *buf, int len) { struct ds_device *dev = (struct ds_device *)data; - ds_write_block(dev, buf, len); + ds_write_block(dev, (u8 *)buf, len); } static u8 ds9490r_read_block(unsigned long data, u8 *buf, int len) diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 0e6ccd4..b460927 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -469,6 +469,8 @@ static void w1_slave_detach(struct w1_slave *sl) device_unregister(&sl->dev); w1_family_put(sl->family); + sl->master->slave_count--; + memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id)); msg.type = W1_SLAVE_REMOVE; w1_netlink_send(sl->master, &msg); @@ -492,6 +494,20 @@ static struct w1_master *w1_search_master(unsigned long data) return (found)?dev:NULL; } +void w1_reconnect_slaves(struct w1_family *f) +{ + struct w1_master *dev; + + spin_lock_bh(&w1_mlock); + list_for_each_entry(dev, &w1_masters, w1_master_entry) { + dev_info(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", + dev->name, f->fid); + set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); + } + spin_unlock_bh(&w1_mlock); +} + + static void w1_slave_found(unsigned long data, u64 rn) { int slave_count; @@ -637,7 +653,7 @@ static int w1_control(void *data) flush_signals(current); list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry) { - if (!control_needs_exit && !dev->need_exit) + if (!control_needs_exit && !dev->flags) continue; /* * Little race: we can create thread but not set the flag. @@ -648,12 +664,8 @@ static int w1_control(void *data) continue; } - spin_lock_bh(&w1_mlock); - list_del(&dev->w1_master_entry); - spin_unlock_bh(&w1_mlock); - if (control_needs_exit) { - dev->need_exit = 1; + set_bit(W1_MASTER_NEED_EXIT, &dev->flags); err = kill_proc(dev->kpid, SIGTERM, 1); if (err) @@ -662,16 +674,42 @@ static int w1_control(void *data) dev->kpid); } - wait_for_completion(&dev->dev_exited); + if (test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { + wait_for_completion(&dev->dev_exited); + spin_lock_bh(&w1_mlock); + list_del(&dev->w1_master_entry); + spin_unlock_bh(&w1_mlock); + + list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { + list_del(&sl->w1_slave_entry); + + w1_slave_detach(sl); + kfree(sl); + } + w1_destroy_master_attributes(dev); + atomic_dec(&dev->refcnt); + continue; + } + + if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) { + dev_info(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name); + down(&dev->mutex); + list_for_each_entry(sl, &dev->slist, w1_slave_entry) { + if (sl->family->fid == W1_FAMILY_DEFAULT) { + struct w1_reg_num rn; + list_del(&sl->w1_slave_entry); + w1_slave_detach(sl); + + memcpy(&rn, &sl->reg_num, sizeof(rn)); - list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { - list_del(&sl->w1_slave_entry); + kfree(sl); - w1_slave_detach(sl); - kfree(sl); + w1_attach_slave_device(dev, &rn); + } + } + clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); + up(&dev->mutex); } - w1_destroy_master_attributes(dev); - atomic_dec(&dev->refcnt); } } @@ -686,14 +724,14 @@ int w1_process(void *data) daemonize("%s", dev->name); allow_signal(SIGTERM); - while (!dev->need_exit) { + while (!test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { try_to_freeze(PF_FREEZE); msleep_interruptible(w1_timeout * 1000); if (signal_pending(current)) flush_signals(current); - if (dev->need_exit) + if (test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) break; if (!dev->initialized) diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 6b5f7be..4f0a986 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h @@ -151,6 +151,9 @@ struct w1_bus_master void (*search)(unsigned long, w1_slave_found_callback); }; +#define W1_MASTER_NEED_EXIT 0 +#define W1_MASTER_NEED_RECONNECT 1 + struct w1_master { struct list_head w1_master_entry; @@ -169,7 +172,8 @@ struct w1_master void *priv; int priv_size; - int need_exit; + long flags; + pid_t kpid; struct semaphore mutex; diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index b8502d9..73e73f6 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c @@ -60,9 +60,10 @@ int w1_register_family(struct w1_family *newf) newf->need_exit = 0; list_add_tail(&newf->family_entry, &w1_families); } - spin_unlock(&w1_flock); + w1_reconnect_slaves(newf); + return ret; } diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index cf18f13..35e85d9 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c @@ -124,10 +124,9 @@ int w1_add_master_device(struct w1_bus_master *master) /* validate minimum functionality */ if (!(master->touch_bit && master->reset_bus) && - !(master->write_bit && master->read_bit)) - { - printk(KERN_ERR "w1_add_master_device: invalid function set\n"); - return(-EINVAL); + !(master->write_bit && master->read_bit)) { + printk(KERN_ERR "w1_add_master_device: invalid function set\n"); + return(-EINVAL); } dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device); @@ -163,7 +162,7 @@ int w1_add_master_device(struct w1_bus_master *master) return 0; err_out_kill_thread: - dev->need_exit = 1; + set_bit(W1_MASTER_NEED_EXIT, &dev->flags); if (kill_proc(dev->kpid, SIGTERM, 1)) dev_err(&dev->dev, "Failed to send signal to w1 kernel thread %d.\n", @@ -181,7 +180,7 @@ void __w1_remove_master_device(struct w1_master *dev) int err; struct w1_netlink_msg msg; - dev->need_exit = 1; + set_bit(W1_MASTER_NEED_EXIT, &dev->flags); err = kill_proc(dev->kpid, SIGTERM, 1); if (err) dev_err(&dev->dev, -- cgit v0.10.2 From e5c515b4532f4aac2b1136612d8c3ecd1891f431 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Fri, 10 Jun 2005 14:53:22 +0400 Subject: [PATCH] w1: fix compiler warnings Signed-off-by: Evgeniy Polyakov diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index 73e73f6..02eee57 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c @@ -27,6 +27,7 @@ DEFINE_SPINLOCK(w1_flock); static LIST_HEAD(w1_families); +extern void w1_reconnect_slaves(struct w1_family *f); static int w1_check_family(struct w1_family *f) { -- cgit v0.10.2 From b3d5496ea5915fa4848fe307af9f7097f312e932 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 2 Apr 2005 20:31:02 +0200 Subject: [PATCH] I2C: Kill address ranges in non-sensors i2c chip drivers Some months ago, you killed the address ranges mechanism from all sensors i2c chip drivers (both the module parameters and the in-code address lists). I think it was a very good move, as the ranges can easily be replaced by individual addresses, and this allowed for significant cleanups in the i2c core (let alone the impressive size shrink for all these drivers). Unfortunately you did not do the same for non-sensors i2c chip drivers. These need the address ranges even less, so we could get rid of the ranges here as well for another significant i2c core cleanup. Here comes a patch which does just that. Since the process is exactly the same as what you did for the other drivers set already, I did not split this one in parts. A documentation update is included. The change saves 308 bytes in the i2c core, and an average 1382 bytes for chip drivers which use I2C_CLIENT_INSMOD, 126 bytes for those which do not. This change is required if we want to merge the sensors and non-sensors i2c code (and we want to do this). Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman Index: gregkh-2.6/Documentation/i2c/writing-clients =================================================================== diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index ad27511..f482dae 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -171,45 +171,31 @@ The following lists are used internally: normal_i2c: filled in by the module writer. A list of I2C addresses which should normally be examined. - normal_i2c_range: filled in by the module writer. - A list of pairs of I2C addresses, each pair being an inclusive range of - addresses which should normally be examined. probe: insmod parameter. A list of pairs. The first value is a bus number (-1 for any I2C bus), the second is the address. These addresses are also probed, as if they were in the 'normal' list. - probe_range: insmod parameter. - A list of triples. The first value is a bus number (-1 for any I2C bus), - the second and third are addresses. These form an inclusive range of - addresses that are also probed, as if they were in the 'normal' list. ignore: insmod parameter. A list of pairs. The first value is a bus number (-1 for any I2C bus), the second is the I2C address. These addresses are never probed. This parameter overrules 'normal' and 'probe', but not the 'force' lists. - ignore_range: insmod parameter. - A list of triples. The first value is a bus number (-1 for any I2C bus), - the second and third are addresses. These form an inclusive range of - I2C addresses that are never probed. - This parameter overrules 'normal' and 'probe', but not the 'force' lists. force: insmod parameter. A list of pairs. The first value is a bus number (-1 for any I2C bus), the second is the I2C address. A device is blindly assumed to be on the given address, no probing is done. -Fortunately, as a module writer, you just have to define the `normal' -and/or `normal_range' parameters. The complete declaration could look -like this: +Fortunately, as a module writer, you just have to define the `normal_i2c' +parameter. The complete declaration could look like this: - /* Scan 0x20 to 0x2f, 0x37, and 0x40 to 0x4f */ - static unsigned short normal_i2c[] = { 0x37,I2C_CLIENT_END }; - static unsigned short normal_i2c_range[] = { 0x20, 0x2f, 0x40, 0x4f, - I2C_CLIENT_END }; + /* Scan 0x37, and 0x48 to 0x4f */ + static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; /* Magic definition of all other variables and things */ I2C_CLIENT_INSMOD; -Note that you *have* to call the two defined variables `normal_i2c' and -`normal_i2c_range', without any prefix! +Note that you *have* to call the defined variable `normal_i2c', +without any prefix! Probing classes (sensors) @@ -223,39 +209,17 @@ The following lists are used internally. They are all lists of integers. normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END. A list of I2C addresses which should normally be examined. - normal_i2c_range: filled in by the module writer. Terminated by - SENSORS_I2C_END - A list of pairs of I2C addresses, each pair being an inclusive range of - addresses which should normally be examined. normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END. A list of ISA addresses which should normally be examined. - normal_isa_range: filled in by the module writer. Terminated by - SENSORS_ISA_END - A list of triples. The first two elements are ISA addresses, being an - range of addresses which should normally be examined. The third is the - modulo parameter: only addresses which are 0 module this value relative - to the first address of the range are actually considered. probe: insmod parameter. Initialize this list with SENSORS_I2C_END values. A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for the ISA bus, -1 for any I2C bus), the second is the address. These addresses are also probed, as if they were in the 'normal' list. - probe_range: insmod parameter. Initialize this list with SENSORS_I2C_END - values. - A list of triples. The first value is a bus number (SENSORS_ISA_BUS for - the ISA bus, -1 for any I2C bus), the second and third are addresses. - These form an inclusive range of addresses that are also probed, as - if they were in the 'normal' list. ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values. A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for the ISA bus, -1 for any I2C bus), the second is the I2C address. These addresses are never probed. This parameter overrules 'normal' and 'probe', but not the 'force' lists. - ignore_range: insmod parameter. Initialize this list with SENSORS_I2C_END - values. - A list of triples. The first value is a bus number (SENSORS_ISA_BUS for - the ISA bus, -1 for any I2C bus), the second and third are addresses. - These form an inclusive range of I2C addresses that are never probed. - This parameter overrules 'normal' and 'probe', but not the 'force' lists. Also used is a list of pointers to sensors_force_data structures: force_data: insmod parameters. A list, ending with an element of which @@ -269,16 +233,14 @@ Also used is a list of pointers to sensors_force_data structures: So we have a generic insmod variabled `force', and chip-specific variables `force_CHIPNAME'. -Fortunately, as a module writer, you just have to define the `normal' -and/or `normal_range' parameters, and define what chip names are used. +Fortunately, as a module writer, you just have to define the `normal_i2c' +and `normal_isa' parameters, and define what chip names are used. The complete declaration could look like this: - /* Scan i2c addresses 0x20 to 0x2f, 0x37, and 0x40 to 0x4f - static unsigned short normal_i2c[] = {0x37,SENSORS_I2C_END}; - static unsigned short normal_i2c_range[] = {0x20,0x2f,0x40,0x4f, - SENSORS_I2C_END}; + /* Scan i2c addresses 0x37, and 0x48 to 0x4f */ + static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; /* Scan ISA address 0x290 */ static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END}; - static unsigned int normal_isa_range[] = {SENSORS_ISA_END}; /* Define chips foo and bar, as well as all module parameters and things */ SENSORS_INSMOD_2(foo,bar); diff --git a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c index ad7ae7a..141b4c2 100644 --- a/drivers/acorn/char/pcf8583.c +++ b/drivers/acorn/char/pcf8583.c @@ -26,11 +26,8 @@ static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, - .normal_i2c_range = ignore, .probe = ignore, - .probe_range = ignore, .ignore = ignore, - .ignore_range = ignore, .force = ignore, }; diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index 7f29a8a..354a262 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -145,7 +145,6 @@ static inline void notresponding(struct isp1301 *isp) static unsigned short normal_i2c[] = { ISP_BASE, ISP_BASE + 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index e771566..5e463c47 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -40,11 +40,8 @@ static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, - .normal_i2c_range = ignore, .probe = ignore, - .probe_range = ignore, .ignore = ignore, - .ignore_range = ignore, .force = ignore, }; diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c index 5a9dedd..30f553e 100644 --- a/drivers/i2c/chips/rtc8564.c +++ b/drivers/i2c/chips/rtc8564.c @@ -66,11 +66,8 @@ static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, - .normal_i2c_range = ignore, .probe = ignore, - .probe_range = ignore, .ignore = ignore, - .ignore_range = ignore, .force = ignore, }; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a22e53b..4cc8c9f 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -742,18 +742,6 @@ int i2c_probe(struct i2c_adapter *adapter, found = 1; } } - for (i = 0; - !found && (address_data->ignore_range[i] != I2C_CLIENT_END); - i += 3) { - if (((adap_id == address_data->ignore_range[i]) || - ((address_data->ignore_range[i]==ANY_I2C_BUS))) && - (addr >= address_data->ignore_range[i+1]) && - (addr <= address_data->ignore_range[i+2])) { - dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, " - "addr %04x\n", adap_id,addr); - found = 1; - } - } if (found) continue; @@ -770,17 +758,6 @@ int i2c_probe(struct i2c_adapter *adapter, } for (i = 0; - !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); - i += 2) { - if ((addr >= address_data->normal_i2c_range[i]) && - (addr <= address_data->normal_i2c_range[i+1])) { - found = 1; - dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, " - "addr %04x\n", adap_id,addr); - } - } - - for (i = 0; !found && (address_data->probe[i] != I2C_CLIENT_END); i += 2) { if (((adap_id == address_data->probe[i]) || @@ -791,18 +768,6 @@ int i2c_probe(struct i2c_adapter *adapter, "addr %04x\n", adap_id,addr); } } - for (i = 0; - !found && (address_data->probe_range[i] != I2C_CLIENT_END); - i += 3) { - if (((adap_id == address_data->probe_range[i]) || - (address_data->probe_range[i] == ANY_I2C_BUS)) && - (addr >= address_data->probe_range[i+1]) && - (addr <= address_data->probe_range[i+2])) { - found = 1; - dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, " - "addr %04x\n", adap_id,addr); - } - } if (!found) continue; diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 0bdb47f..61400f0 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -51,8 +51,10 @@ static int do_probe( struct i2c_adapter *adapter, int addr, int kind); /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ -static unsigned short normal_i2c[] = { 0x49, 0x2c, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, 0x2c, 0x2f, I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, + 0x2c, 0x2d, 0x2e, 0x2f, + I2C_CLIENT_END }; I2C_CLIENT_INSMOD; diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c index 80254ca..e9bf339 100644 --- a/drivers/media/video/adv7170.c +++ b/drivers/media/video/adv7170.c @@ -384,21 +384,15 @@ static unsigned short normal_i2c[] = I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, .probe = probe, - .probe_range = probe_range, .ignore = ignore, - .ignore_range = ignore_range, .force = force }; diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index 95d0974..2d5fa44 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c @@ -434,21 +434,15 @@ static unsigned short normal_i2c[] = I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, .probe = probe, - .probe_range = probe_range, .ignore = ignore, - .ignore_range = ignore_range, .force = force }; diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index cf0db25..31d5185 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -500,21 +500,15 @@ static unsigned short normal_i2c[] = { I2C_BT819 >> 1, I2C_CLIENT_END, }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, .probe = probe, - .probe_range = probe_range, .ignore = ignore, - .ignore_range = ignore_range, .force = force }; diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c index efe605a..07f72f64 100644 --- a/drivers/media/video/bt832.c +++ b/drivers/media/video/bt832.c @@ -39,8 +39,8 @@ MODULE_LICENSE("GPL"); /* Addresses to scan */ -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_BT832_ALT1>>1,I2C_BT832_ALT2>>1,I2C_CLIENT_END}; +static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1, + I2C_CLIENT_END }; I2C_CLIENT_INSMOD; /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c index 72c7eb0..59121a0 100644 --- a/drivers/media/video/bt856.c +++ b/drivers/media/video/bt856.c @@ -288,21 +288,15 @@ bt856_command (struct i2c_client *client, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, .probe = probe, - .probe_range = probe_range, .ignore = ignore, - .ignore_range = ignore_range, .force = force }; diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 7fbb858..09464d6 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -147,7 +147,6 @@ static unsigned short normal_i2c[] = { I2C_MSP3400C_ALT >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END}; I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index ba69f09..b8054da 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -64,7 +64,6 @@ static struct video_device saa_template; /* Declared near bottom */ /* Addresses to scan */ static unsigned short normal_i2c[] = { I2C_ADDRESS, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; static struct i2c_client client_template; diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index d74caa1..7ffa2e9 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c @@ -132,7 +132,6 @@ static struct video_device saa_template; /* Declared near bottom */ /* Addresses to scan */ static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; I2C_CLIENT_INSMOD; static struct i2c_client client_template; diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c index 64273b4..90b0a0b 100644 --- a/drivers/media/video/saa7110.c +++ b/drivers/media/video/saa7110.c @@ -463,21 +463,15 @@ static unsigned short normal_i2c[] = { (I2C_SAA7110 >> 1) + 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, .probe = probe, - .probe_range = probe_range, .ignore = ignore, - .ignore_range = ignore_range, .force = force }; diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c index 0a87311..e305a89 100644 --- a/drivers/media/video/saa7111.c +++ b/drivers/media/video/saa7111.c @@ -482,21 +482,15 @@ saa7111_command (struct i2c_client *client, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, .probe = probe, - .probe_range = probe_range, .ignore = ignore, - .ignore_range = ignore_range, .force = force }; diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c index e730236..1ca4e70 100644 --- a/drivers/media/video/saa7114.c +++ b/drivers/media/video/saa7114.c @@ -820,21 +820,15 @@ saa7114_command (struct i2c_client *client, */ static unsigned short normal_i2c[] = { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, .probe = probe, - .probe_range = probe_range, .ignore = ignore, - .ignore_range = ignore_range, .force = force }; diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 1db0226..42c2b56 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -22,7 +22,6 @@ /* Addresses to scan */ static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; I2C_CLIENT_INSMOD; MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder"); diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c index 5f0b224..5c623fa 100644 --- a/drivers/media/video/saa7185.c +++ b/drivers/media/video/saa7185.c @@ -380,21 +380,15 @@ saa7185_command (struct i2c_client *client, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, .probe = probe, - .probe_range = probe_range, .ignore = ignore, - .ignore_range = ignore_range, .force = force }; diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 376a4a4..07ba6d3 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -74,7 +74,6 @@ static unsigned short normal_i2c[] = { I2C_TDA7432 >> 1, I2C_CLIENT_END, }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; /* Structure of address and subaddresses for the tda7432 */ diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c index b5177c6..c29bdfc 100644 --- a/drivers/media/video/tda9840.c +++ b/drivers/media/video/tda9840.c @@ -43,7 +43,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); /* addresses to scan, found only at 0x42 (7-Bit) */ static unsigned short normal_i2c[] = { I2C_TDA9840, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; /* magic definition of all other variables and things */ I2C_CLIENT_INSMOD; diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 4f1114c..97b113e 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -44,7 +44,6 @@ static unsigned short normal_i2c[] = { I2C_TDA9875 >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; I2C_CLIENT_INSMOD; /* This is a superset of the TDA9875 */ diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index debef19..7e6e6dd 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -33,7 +33,6 @@ static unsigned short normal_i2c[] = { 0x96 >>1, I2C_CLIENT_END, }; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END}; I2C_CLIENT_INSMOD; /* insmod options */ diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index 3ec3955..b44db8a 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c @@ -43,7 +43,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); /* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */ static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; /* magic definition of all other variables and things */ I2C_CLIENT_INSMOD; diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index bd10710..48d4db7 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c @@ -40,7 +40,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); /* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */ static unsigned short normal_i2c[] = { I2C_TEA6420_1, I2C_TEA6420_2, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; /* magic definition of all other variables and things */ I2C_CLIENT_INSMOD; diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c index 6b20aa9..bedb15e 100644 --- a/drivers/media/video/tuner-3036.c +++ b/drivers/media/video/tuner-3036.c @@ -34,19 +34,16 @@ static int this_adap; static struct i2c_client client_template; /* Addresses to scan */ -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {0x60, 0x61, I2C_CLIENT_END}; +static unsigned short normal_i2c[] = { 0x60, 0x61, I2C_CLIENT_END }; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force + .normal_i2c = normal_i2c, + .probe = probe, + .ignore = ignore, + .force = force, }; /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 6212388e..81882dd 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -28,10 +28,8 @@ /* standard i2c insmod options */ static unsigned short normal_i2c[] = { 0x4b, /* tda8290 */ - I2C_CLIENT_END -}; -static unsigned short normal_i2c_range[] = { - 0x60, 0x6f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; @@ -225,9 +223,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) static int tuner_probe(struct i2c_adapter *adap) { if (0 != addr) { - normal_i2c[0] = addr; - normal_i2c_range[0] = addr; - normal_i2c_range[1] = addr; + normal_i2c[0] = addr; + normal_i2c[1] = I2C_CLIENT_END; } this_adap = 0; diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 80dc34f..41b635e 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -148,7 +148,6 @@ static unsigned short normal_i2c[] = { I2C_TDA9874 >> 1, I2C_PIC16C54 >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; static struct i2c_driver driver; diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index e1443a0..3d21697 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -482,7 +482,6 @@ static unsigned short normal_i2c[] = { 0xa0 >> 1, I2C_CLIENT_END, }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; struct i2c_driver i2c_driver_tveeprom; diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 0fd6c9a..b970369 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c @@ -569,21 +569,15 @@ static unsigned short normal_i2c[] = { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, .probe = probe, - .probe_range = probe_range, .ignore = ignore, - .ignore_range = ignore_range, .force = force }; diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index e529841..67f8534 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -1230,7 +1230,6 @@ static int maven_shutdown_client(struct i2c_client* clnt) { } static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; static struct i2c_driver maven_driver; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index ebcd745..be837b1 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -290,11 +290,8 @@ static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data) */ struct i2c_client_address_data { unsigned short *normal_i2c; - unsigned short *normal_i2c_range; unsigned short *probe; - unsigned short *probe_range; unsigned short *ignore; - unsigned short *ignore_range; unsigned short *force; }; @@ -563,24 +560,15 @@ union i2c_smbus_data { #define I2C_CLIENT_INSMOD \ I2C_CLIENT_MODULE_PARM(probe, \ "List of adapter,address pairs to scan additionally"); \ - I2C_CLIENT_MODULE_PARM(probe_range, \ - "List of adapter,start-addr,end-addr triples to scan " \ - "additionally"); \ I2C_CLIENT_MODULE_PARM(ignore, \ "List of adapter,address pairs not to scan"); \ - I2C_CLIENT_MODULE_PARM(ignore_range, \ - "List of adapter,start-addr,end-addr triples not to " \ - "scan"); \ I2C_CLIENT_MODULE_PARM(force, \ "List of adapter,address pairs to boldly assume " \ "to be present"); \ static struct i2c_client_address_data addr_data = { \ .normal_i2c = normal_i2c, \ - .normal_i2c_range = normal_i2c_range, \ .probe = probe, \ - .probe_range = probe_range, \ .ignore = ignore, \ - .ignore_range = ignore_range, \ .force = force, \ } -- cgit v0.10.2 From 68cc9d0b714d7d533c0cfc257a62f7f7f4f22a11 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 2 Apr 2005 20:04:41 +0200 Subject: [PATCH] I2C: Merge unused address lists in some video drivers On top of my previous patch which removes the use of address ranges in video i2c drivers, this one can save an additional few bytes of memory. Most of these drivers which do not use I2C_CLIENT_INSMOD initialize the unused address lists in a less than optimal way. This patch simply optimizes this, by using a single one-element list instead of 3 different lists with two elements each. This saves an average 63 bytes on these drivers. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff -ruN linux-2.6.12-rc1-bk5.orig/drivers/media/video/adv7170.c linux-2.6.12-rc1-bk5/drivers/media/video/adv7170.c diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c index e9bf339..48989ed 100644 --- a/drivers/media/video/adv7170.c +++ b/drivers/media/video/adv7170.c @@ -385,15 +385,13 @@ static unsigned short normal_i2c[] = I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .probe = probe, - .ignore = ignore, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_adv7170; diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index 2d5fa44..f898b65 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c @@ -435,15 +435,13 @@ static unsigned short normal_i2c[] = I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .probe = probe, - .ignore = ignore, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_adv7175; diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index 31d5185..8733588 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -501,15 +501,13 @@ static unsigned short normal_i2c[] = { I2C_CLIENT_END, }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .probe = probe, - .ignore = ignore, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_bt819; diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c index 59121a0..a5d529c 100644 --- a/drivers/media/video/bt856.c +++ b/drivers/media/video/bt856.c @@ -289,15 +289,13 @@ bt856_command (struct i2c_client *client, */ static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .probe = probe, - .ignore = ignore, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_bt856; diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c index 90b0a0b..22d055d 100644 --- a/drivers/media/video/saa7110.c +++ b/drivers/media/video/saa7110.c @@ -464,15 +464,13 @@ static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .probe = probe, - .ignore = ignore, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_saa7110; diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c index e305a89..fcd8973 100644 --- a/drivers/media/video/saa7111.c +++ b/drivers/media/video/saa7111.c @@ -483,15 +483,13 @@ saa7111_command (struct i2c_client *client, */ static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .probe = probe, - .ignore = ignore, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_saa7111; diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c index 1ca4e70..2ba997f 100644 --- a/drivers/media/video/saa7114.c +++ b/drivers/media/video/saa7114.c @@ -821,15 +821,13 @@ saa7114_command (struct i2c_client *client, static unsigned short normal_i2c[] = { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .probe = probe, - .ignore = ignore, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_saa7114; diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c index 5c623fa..108e7a4 100644 --- a/drivers/media/video/saa7185.c +++ b/drivers/media/video/saa7185.c @@ -381,15 +381,13 @@ saa7185_command (struct i2c_client *client, */ static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .probe = probe, - .ignore = ignore, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_saa7185; diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c index bedb15e..51748c6 100644 --- a/drivers/media/video/tuner-3036.c +++ b/drivers/media/video/tuner-3036.c @@ -35,15 +35,13 @@ static struct i2c_client client_template; /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x60, 0x61, I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .probe = probe, - .ignore = ignore, - .force = force, + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index b970369..5dbd9f6 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c @@ -570,15 +570,13 @@ static unsigned short normal_i2c[] = I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .probe = probe, - .ignore = ignore, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver vpx3220_i2c_driver; -- cgit v0.10.2 From 792f156d61d327671f58829dc04ad5609152e393 Mon Sep 17 00:00:00 2001 From: Clemens Koller Date: Mon, 11 Apr 2005 11:49:14 +0200 Subject: [PATCH] I2C: rtc8564.c remove duplicate include [PATCH] I2C rtc8564.c remove duplicate include Trivial fix: removes duplicate include line. Signed-off-by: Clemens Koller Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c index 30f553e..588fc22 100644 --- a/drivers/i2c/chips/rtc8564.c +++ b/drivers/i2c/chips/rtc8564.c @@ -19,7 +19,6 @@ #include #include /* get the user-level API */ #include -#include #include "rtc8564.h" -- cgit v0.10.2 From 3886246a257e828248ce1e72ced00408a3557f0d Mon Sep 17 00:00:00 2001 From: Sebastian Witt Date: Wed, 13 Apr 2005 22:25:39 +0200 Subject: [PATCH] I2C: i2c-vid.h: Support for VID to reg conversion Adds conversion from VID (mV) to register value. Used by the atxp1 I2C module. Removed uneeded switch case. Signed-off-by: Sebastian Witt Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/i2c-vid.h b/include/linux/i2c-vid.h index 974835e3..41d0635 100644 --- a/include/linux/i2c-vid.h +++ b/include/linux/i2c-vid.h @@ -97,3 +97,15 @@ static inline int vid_from_reg(int val, int vrm) 2050 - (val) * 50); } } + +static inline int vid_to_reg(int val, int vrm) +{ + switch (vrm) { + case 91: /* VRM 9.1 */ + case 90: /* VRM 9.0 */ + return ((val >= 1100) && (val <= 1850) ? + ((18499 - val * 10) / 25 + 5) / 10 : -1); + default: + return -1; + } +} -- cgit v0.10.2 From 9cb7d18433ea6db04b3999e8d0b8f52fba551c2d Mon Sep 17 00:00:00 2001 From: Sebastian Witt Date: Wed, 13 Apr 2005 22:27:53 +0200 Subject: [PATCH] I2C: add new atxp1 driver Adds support for the Attansic ATXP1 I2C device, found on some x86 plattforms to change CPU and other voltages. Depends on the previous i2c-vid.h patch. Signed-off-by: Sebastian Witt Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 74d23cf..a408c13 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -62,6 +62,19 @@ config SENSORS_ASB100 This driver can also be built as a module. If so, the module will be called asb100. +config SENSORS_ATXP1 + tristate "Attansic ATXP1 VID controller" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Attansic ATXP1 VID + controller. + + If your board have such a chip, you are able to control your CPU + core and other voltages. + + This driver can also be built as a module. If so, the module + will be called atxp1. + config SENSORS_DS1621 tristate "Dallas Semiconductor DS1621 and DS1625" depends on I2C && EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 6559916..6fadd78 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o +obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_DS1337) += ds1337.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o diff --git a/drivers/i2c/chips/atxp1.c b/drivers/i2c/chips/atxp1.c new file mode 100644 index 0000000..570b36c --- /dev/null +++ b/drivers/i2c/chips/atxp1.c @@ -0,0 +1,361 @@ +/* + atxp1.c - kernel module for setting CPU VID and general purpose + I/Os using the Attansic ATXP1 chip. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); +MODULE_VERSION("0.6.2"); +MODULE_AUTHOR("Sebastian Witt "); + +#define ATXP1_VID 0x00 +#define ATXP1_CVID 0x01 +#define ATXP1_GPIO1 0x06 +#define ATXP1_GPIO2 0x0a +#define ATXP1_VIDENA 0x20 +#define ATXP1_VIDMASK 0x1f +#define ATXP1_GPIO1MASK 0x0f + +static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +SENSORS_INSMOD_1(atxp1); + +static int atxp1_attach_adapter(struct i2c_adapter * adapter); +static int atxp1_detach_client(struct i2c_client * client); +static struct atxp1_data * atxp1_update_device(struct device *dev); +static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind); + +static struct i2c_driver atxp1_driver = { + .owner = THIS_MODULE, + .name = "atxp1", + .flags = I2C_DF_NOTIFY, + .attach_adapter = atxp1_attach_adapter, + .detach_client = atxp1_detach_client, +}; + +struct atxp1_data { + struct i2c_client client; + struct semaphore update_lock; + unsigned long last_updated; + u8 valid; + struct { + u8 vid; /* VID output register */ + u8 cpu_vid; /* VID input from CPU */ + u8 gpio1; /* General purpose I/O register 1 */ + u8 gpio2; /* General purpose I/O register 2 */ + } reg; + u8 vrm; /* Detected CPU VRM */ +}; + +static struct atxp1_data * atxp1_update_device(struct device *dev) +{ + struct i2c_client *client; + struct atxp1_data *data; + + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ) || + (jiffies < data->last_updated) || + !data->valid) { + + /* Update local register data */ + data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID); + data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID); + data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1); + data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2); + + data->valid = 1; + } + + up(&data->update_lock); + + return(data); +} + +/* sys file functions for cpu0_vid */ +ssize_t atxp1_showvcore(struct device *dev, char *buf) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm)); + + return size; +} + +ssize_t atxp1_storevcore(struct device *dev, const char* buf, size_t count) +{ + struct atxp1_data *data; + struct i2c_client *client; + char vid; + char cvid; + unsigned int vcore; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + vcore = simple_strtoul(buf, NULL, 10); + vcore /= 25; + vcore *= 25; + + /* Calculate VID */ + vid = vid_to_reg(vcore, data->vrm); + + if (vid < 0) { + dev_err(dev, "VID calculation failed.\n"); + return -1; + } + + /* If output enabled, use control register value. Otherwise original CPU VID */ + if (data->reg.vid & ATXP1_VIDENA) + cvid = data->reg.vid & ATXP1_VIDMASK; + else + cvid = data->reg.cpu_vid; + + /* Nothing changed, aborting */ + if (vid == cvid) + return count; + + dev_info(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid); + + /* Write every 25 mV step to increase stability */ + if (cvid > vid) { + for (; cvid >= vid; cvid--) { + i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); + } + } + else { + for (; cvid <= vid; cvid++) { + i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); + } + } + + data->valid = 0; + + return count; +} + +/* CPU core reference voltage + unit: millivolt +*/ +static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore); + +/* sys file functions for GPIO1 */ +ssize_t atxp1_showgpio1(struct device *dev, char *buf) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK); + + return size; +} + +ssize_t atxp1_storegpio1(struct device *dev, const char* buf, size_t count) +{ + struct atxp1_data *data; + struct i2c_client *client; + unsigned int value; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + value = simple_strtoul(buf, NULL, 16); + + value &= ATXP1_GPIO1MASK; + + if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) { + dev_info(dev, "Writing 0x%x to GPIO1.\n", value); + + i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value); + + data->valid = 0; + } + + return count; +} + +/* GPIO1 data register + unit: Four bit as hex (e.g. 0x0f) +*/ +static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); + +/* sys file functions for GPIO2 */ +ssize_t atxp1_showgpio2(struct device *dev, char *buf) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "0x%02x\n", data->reg.gpio2); + + return size; +} + +ssize_t atxp1_storegpio2(struct device *dev, const char* buf, size_t count) +{ + struct atxp1_data *data; + struct i2c_client *client; + unsigned int value; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + value = simple_strtoul(buf, NULL, 16) & 0xff; + + if (value != data->reg.gpio2) { + dev_info(dev, "Writing 0x%x to GPIO1.\n", value); + + i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value); + + data->valid = 0; + } + + return count; +} + +/* GPIO2 data register + unit: Eight bit as hex (e.g. 0xff) +*/ +static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); + + +static int atxp1_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, &atxp1_detect); +}; + +static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client * new_client; + struct atxp1_data * data; + int err = 0; + u8 temp; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(data, 0, sizeof(struct atxp1_data)); + new_client = &data->client; + i2c_set_clientdata(new_client, data); + + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &atxp1_driver; + new_client->flags = 0; + + /* Detect ATXP1, checking if vendor ID registers are all zero */ + if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) && + (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) && + (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) && + (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) { + + /* No vendor ID, now checking if registers 0x10,0x11 (non-existent) + * showing the same as register 0x00 */ + temp = i2c_smbus_read_byte_data(new_client, 0x00); + + if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) && + (i2c_smbus_read_byte_data(new_client, 0x11) == temp) )) + goto exit_free; + } + + /* Get VRM */ + data->vrm = i2c_which_vrm(); + + if ((data->vrm != 90) && (data->vrm != 91)) { + dev_err(&new_client->dev, "Not supporting VRM %d.%d\n", + data->vrm / 10, data->vrm % 10); + goto exit_free; + } + + strncpy(new_client->name, "atxp1", I2C_NAME_SIZE); + + data->valid = 0; + + init_MUTEX(&data->update_lock); + + err = i2c_attach_client(new_client); + + if (err) + { + dev_err(&new_client->dev, "Attach client error.\n"); + goto exit_free; + } + + device_create_file(&new_client->dev, &dev_attr_gpio1); + device_create_file(&new_client->dev, &dev_attr_gpio2); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + + dev_info(&new_client->dev, "Using VRM: %d.%d\n", + data->vrm / 10, data->vrm % 10); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +}; + +static int atxp1_detach_client(struct i2c_client * client) +{ + int err; + + err = i2c_detach_client(client); + + if (err) + dev_err(&client->dev, "Failed to detach client.\n"); + else + kfree(i2c_get_clientdata(client)); + + return err; +}; + +static int __init atxp1_init(void) +{ + return i2c_add_driver(&atxp1_driver); +}; + +static void __exit atxp1_exit(void) +{ + i2c_del_driver(&atxp1_driver); +}; + +module_init(atxp1_init); +module_exit(atxp1_exit); -- cgit v0.10.2 From 69113efac29e5f1b7a03dd4fdca5ede6901f4eb8 Mon Sep 17 00:00:00 2001 From: Greg K-H Date: Tue, 5 Apr 2005 18:00:47 +0200 Subject: [PATCH] I2C: mark all functions static in atxp1 driver Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/atxp1.c b/drivers/i2c/chips/atxp1.c index 570b36c..57b0bdd 100644 --- a/drivers/i2c/chips/atxp1.c +++ b/drivers/i2c/chips/atxp1.c @@ -99,7 +99,7 @@ static struct atxp1_data * atxp1_update_device(struct device *dev) } /* sys file functions for cpu0_vid */ -ssize_t atxp1_showvcore(struct device *dev, char *buf) +static ssize_t atxp1_showvcore(struct device *dev, char *buf) { int size; struct atxp1_data *data; @@ -111,7 +111,7 @@ ssize_t atxp1_showvcore(struct device *dev, char *buf) return size; } -ssize_t atxp1_storevcore(struct device *dev, const char* buf, size_t count) +static ssize_t atxp1_storevcore(struct device *dev, const char* buf, size_t count) { struct atxp1_data *data; struct i2c_client *client; @@ -169,7 +169,7 @@ ssize_t atxp1_storevcore(struct device *dev, const char* buf, size_t count) static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore); /* sys file functions for GPIO1 */ -ssize_t atxp1_showgpio1(struct device *dev, char *buf) +static ssize_t atxp1_showgpio1(struct device *dev, char *buf) { int size; struct atxp1_data *data; @@ -181,7 +181,7 @@ ssize_t atxp1_showgpio1(struct device *dev, char *buf) return size; } -ssize_t atxp1_storegpio1(struct device *dev, const char* buf, size_t count) +static ssize_t atxp1_storegpio1(struct device *dev, const char* buf, size_t count) { struct atxp1_data *data; struct i2c_client *client; @@ -211,7 +211,7 @@ ssize_t atxp1_storegpio1(struct device *dev, const char* buf, size_t count) static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); /* sys file functions for GPIO2 */ -ssize_t atxp1_showgpio2(struct device *dev, char *buf) +static ssize_t atxp1_showgpio2(struct device *dev, char *buf) { int size; struct atxp1_data *data; @@ -223,7 +223,7 @@ ssize_t atxp1_showgpio2(struct device *dev, char *buf) return size; } -ssize_t atxp1_storegpio2(struct device *dev, const char* buf, size_t count) +static ssize_t atxp1_storegpio2(struct device *dev, const char* buf, size_t count) { struct atxp1_data *data; struct i2c_client *client; -- cgit v0.10.2 From 3e9d0ba1305cd7c6efd2ab3a003e58a27da1796b Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Fri, 8 Apr 2005 15:00:21 +0200 Subject: [PATCH] I2C: ds1337 1/4 Use i2c_transfer to send message, so we get proper bus locking. Signed-off-by: Ladislav Michl Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 07f16c3..e2a6aab 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -3,7 +3,7 @@ * * Copyright (C) 2005 James Chapman * - * based on linux/drivers/acron/char/pcf8583.c + * based on linux/drivers/acorn/char/pcf8583.c * Copyright (C) 2000 Russell King * * This program is free software; you can redistribute it and/or modify @@ -119,8 +119,7 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) msg[1].len = sizeof(buf); msg[1].buf = &buf[0]; - result = client->adapter->algo->master_xfer(client->adapter, - &msg[0], 2); + result = i2c_transfer(client->adapter, msg, 2); dev_dbg(&client->adapter->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n", @@ -194,8 +193,7 @@ static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) msg[0].len = sizeof(buf); msg[0].buf = &buf[0]; - result = client->adapter->algo->master_xfer(client->adapter, - &msg[0], 1); + result = i2c_transfer(client->adapter, msg, 1); if (result < 0) { dev_err(&client->adapter->dev, "ds1337[%d]: error " "writing data! %d\n", data->id, result); -- cgit v0.10.2 From 6069ffde15472da9d041a58df490d388bb175d51 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Fri, 8 Apr 2005 15:02:16 +0200 Subject: [PATCH] I2C: ds1337 2/4 Use correct macros to convert between bdc and bin. See linux/bcd.h Signed-off-by: Ladislav Michl Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index e2a6aab..8a9e751 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -127,15 +127,15 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) buf[4], buf[5], buf[6]); if (result >= 0) { - dt->tm_sec = BCD_TO_BIN(buf[0]); - dt->tm_min = BCD_TO_BIN(buf[1]); + dt->tm_sec = BCD2BIN(buf[0]); + dt->tm_min = BCD2BIN(buf[1]); val = buf[2] & 0x3f; - dt->tm_hour = BCD_TO_BIN(val); - dt->tm_wday = BCD_TO_BIN(buf[3]) - 1; - dt->tm_mday = BCD_TO_BIN(buf[4]); + dt->tm_hour = BCD2BIN(val); + dt->tm_wday = BCD2BIN(buf[3]) - 1; + dt->tm_mday = BCD2BIN(buf[4]); val = buf[5] & 0x7f; - dt->tm_mon = BCD_TO_BIN(val); - dt->tm_year = 1900 + BCD_TO_BIN(buf[6]); + dt->tm_mon = BCD2BIN(val); + dt->tm_year = 1900 + BCD2BIN(buf[6]); if (buf[5] & 0x80) dt->tm_year += 100; @@ -174,19 +174,19 @@ static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); buf[0] = 0; /* reg offset */ - buf[1] = BIN_TO_BCD(dt->tm_sec); - buf[2] = BIN_TO_BCD(dt->tm_min); - buf[3] = BIN_TO_BCD(dt->tm_hour) | (1 << 6); - buf[4] = BIN_TO_BCD(dt->tm_wday) + 1; - buf[5] = BIN_TO_BCD(dt->tm_mday); - buf[6] = BIN_TO_BCD(dt->tm_mon); + buf[1] = BIN2BCD(dt->tm_sec); + buf[2] = BIN2BCD(dt->tm_min); + buf[3] = BIN2BCD(dt->tm_hour) | (1 << 6); + buf[4] = BIN2BCD(dt->tm_wday) + 1; + buf[5] = BIN2BCD(dt->tm_mday); + buf[6] = BIN2BCD(dt->tm_mon); if (dt->tm_year >= 2000) { val = dt->tm_year - 2000; buf[6] |= (1 << 7); } else { val = dt->tm_year - 1900; } - buf[7] = BIN_TO_BCD(val); + buf[7] = BIN2BCD(val); msg[0].addr = client->addr; msg[0].flags = 0; -- cgit v0.10.2 From d01b79d0613ebb6810bb48baf6e53e9319701fea Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Fri, 8 Apr 2005 15:06:39 +0200 Subject: [PATCH] I2C: ds1337 3/4 dev_{dbg,err} functions should print client's device name. data->id can be dropped from message, because device is determined by bus it hangs on (it has fixed address). Signed-off-by: Ladislav Michl Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 8a9e751..89fc02b 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -95,7 +95,6 @@ static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) */ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) { - struct ds1337_data *data = i2c_get_clientdata(client); int result; u8 buf[7]; u8 val; @@ -103,9 +102,7 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) u8 offs = 0; if (!dt) { - dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n", - __FUNCTION__); - + dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__); return -EINVAL; } @@ -121,8 +118,7 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) result = i2c_transfer(client->adapter, msg, 2); - dev_dbg(&client->adapter->dev, - "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n", + dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n", __FUNCTION__, result, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); @@ -139,14 +135,13 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) if (buf[5] & 0x80) dt->tm_year += 100; - dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, " + dev_dbg(&client->dev, "%s: secs=%d, mins=%d, " "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, dt->tm_sec, dt->tm_min, dt->tm_hour, dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); } else { - dev_err(&client->adapter->dev, "ds1337[%d]: error reading " - "data! %d\n", data->id, result); + dev_err(&client->dev, "error reading data! %d\n", result); result = -EIO; } @@ -155,20 +150,17 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) { - struct ds1337_data *data = i2c_get_clientdata(client); int result; u8 buf[8]; u8 val; struct i2c_msg msg[1]; if (!dt) { - dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n", - __FUNCTION__); - + dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__); return -EINVAL; } - dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, hours=%d, " + dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, dt->tm_sec, dt->tm_min, dt->tm_hour, dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); @@ -195,8 +187,7 @@ static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) result = i2c_transfer(client->adapter, msg, 1); if (result < 0) { - dev_err(&client->adapter->dev, "ds1337[%d]: error " - "writing data! %d\n", data->id, result); + dev_err(&client->dev, "error writing data! %d\n", result); result = -EIO; } else { result = 0; @@ -208,7 +199,7 @@ static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) static int ds1337_command(struct i2c_client *client, unsigned int cmd, void *arg) { - dev_dbg(&client->adapter->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); + dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); switch (cmd) { case DS1337_GET_DATE: -- cgit v0.10.2 From 0b46e334d77b2d3b8b3aa665c81c4afbe9f1f458 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Wed, 4 May 2005 08:13:13 +0200 Subject: [PATCH] I2C: ds1337: Make time format consistent with other RTC drivers Make time format consistent with other RTC drivers. Signed-off-by: Ladislav Michl Signed-off-by: James Chapman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 89fc02b..0967ec6 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -130,8 +130,8 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) dt->tm_wday = BCD2BIN(buf[3]) - 1; dt->tm_mday = BCD2BIN(buf[4]); val = buf[5] & 0x7f; - dt->tm_mon = BCD2BIN(val); - dt->tm_year = 1900 + BCD2BIN(buf[6]); + dt->tm_mon = BCD2BIN(val) - 1; + dt->tm_year = BCD2BIN(buf[6]); if (buf[5] & 0x80) dt->tm_year += 100; @@ -171,12 +171,11 @@ static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) buf[3] = BIN2BCD(dt->tm_hour) | (1 << 6); buf[4] = BIN2BCD(dt->tm_wday) + 1; buf[5] = BIN2BCD(dt->tm_mday); - buf[6] = BIN2BCD(dt->tm_mon); - if (dt->tm_year >= 2000) { - val = dt->tm_year - 2000; + buf[6] = BIN2BCD(dt->tm_mon) + 1; + val = dt->tm_year; + if (val >= 100) { + val -= 100; buf[6] |= (1 << 7); - } else { - val = dt->tm_year - 1900; } buf[7] = BIN2BCD(val); -- cgit v0.10.2 From 00588243053bb40d0406c7843833f8fae81294ab Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Wed, 4 May 2005 08:13:54 +0200 Subject: [PATCH] I2C: ds1337: i2c_transfer() checking i2c_transfer returns number of sucessfully transfered messages. Change error checking to accordingly. (ds1337_set_datetime never returned sucess) Signed-off-by: Ladislav Michl Signed-off-by: James Chapman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 0967ec6..c4762ac 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -122,7 +122,7 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) __FUNCTION__, result, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - if (result >= 0) { + if (result == 2) { dt->tm_sec = BCD2BIN(buf[0]); dt->tm_min = BCD2BIN(buf[1]); val = buf[2] & 0x3f; @@ -140,12 +140,12 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) __FUNCTION__, dt->tm_sec, dt->tm_min, dt->tm_hour, dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); - } else { - dev_err(&client->dev, "error reading data! %d\n", result); - result = -EIO; + + return 0; } - return result; + dev_err(&client->dev, "error reading data! %d\n", result); + return -EIO; } static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) @@ -185,14 +185,11 @@ static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) msg[0].buf = &buf[0]; result = i2c_transfer(client->adapter, msg, 1); - if (result < 0) { - dev_err(&client->dev, "error writing data! %d\n", result); - result = -EIO; - } else { - result = 0; - } + if (result == 1) + return 0; - return result; + dev_err(&client->dev, "error writing data! %d\n", result); + return -EIO; } static int ds1337_command(struct i2c_client *client, unsigned int cmd, -- cgit v0.10.2 From 86919833dbeac668762ae7056ead2d35d070f622 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Wed, 4 May 2005 08:14:38 +0200 Subject: [PATCH] I2C: ds1337: search by bus number Chip is searched by bus number rather than its own proprietary id. Signed-off-by: Ladislav Michl Signed-off-by: James Chapman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index c4762ac..8ee818c 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -69,13 +69,11 @@ static struct i2c_driver ds1337_driver = { struct ds1337_data { struct i2c_client client; struct list_head list; - int id; }; /* * Internal variables */ -static int ds1337_id; static LIST_HEAD(ds1337_clients); static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) @@ -213,7 +211,7 @@ static int ds1337_command(struct i2c_client *client, unsigned int cmd, * Public API for access to specific device. Useful for low-level * RTC access from kernel code. */ -int ds1337_do_command(int id, int cmd, void *arg) +int ds1337_do_command(int bus, int cmd, void *arg) { struct list_head *walk; struct list_head *tmp; @@ -221,7 +219,7 @@ int ds1337_do_command(int id, int cmd, void *arg) list_for_each_safe(walk, tmp, &ds1337_clients) { data = list_entry(walk, struct ds1337_data, list); - if (data->id == id) + if (data->client.adapter->nr == bus) return ds1337_command(&data->client, cmd, arg); } @@ -331,7 +329,6 @@ static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind) ds1337_init_client(new_client); /* Add client to local list */ - data->id = ds1337_id++; list_add(&data->list, &ds1337_clients); return 0; -- cgit v0.10.2 From 912b9c0c52b95696165e84d67fdab2af81a2213e Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Tue, 10 May 2005 14:08:04 +0200 Subject: [PATCH] ds1337 driver works also with ds1339 chip On Wed, May 04, 2005 at 12:07:11PM +0200, Jean Delvare wrote: > Additionally, I would welcome an additional patch documenting the fact > that the ds1337 driver will work fine with the Dallas DS1339 real-time > clock chip. Document the fact that ds1337 driver works also with DS1339 real-time clock chip. Signed-off-by: Ladislav Michl Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index a408c13..67be4c9 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -379,12 +379,12 @@ menu "Other I2C Chip support" depends on I2C config SENSORS_DS1337 - tristate "Dallas Semiconductor DS1337 Real Time Clock" + tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock" depends on I2C && EXPERIMENTAL select I2C_SENSOR help If you say yes here you get support for Dallas Semiconductor - DS1337 real-time clock chips. + DS1337 and DS1339 real-time clock chips. This driver can also be built as a module. If so, the module will be called ds1337. diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 8ee818c..2d12cc8 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -10,7 +10,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Driver for Dallas Semiconductor DS1337 real time clock chip + * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip */ #include -- cgit v0.10.2 From da17838c5e7256976c34c5d051dc8fb3c6f364b7 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Wed, 11 May 2005 10:32:54 +0200 Subject: [PATCH] ds1337: export ds1337_do_command Signed-off-by: Ladislav Michl Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 2d12cc8..36bb383 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -380,5 +380,7 @@ MODULE_AUTHOR("James Chapman "); MODULE_DESCRIPTION("DS1337 RTC driver"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL_GPL(ds1337_do_command); + module_init(ds1337_init); module_exit(ds1337_exit); -- cgit v0.10.2 From f0bb60e7b1a0a26c25d8cbf81dda7afbc8bd2982 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 16 Apr 2005 18:10:02 +0000 Subject: [PATCH] I2C: drivers/i2c/*: #include cleanup Files that don't use CONFIG_* stuff shouldn't include config.h Files that use CONFIG_* stuff should include config.h It's that simple. ;-) Signed-off-by: Alexey Dobriyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c index 35789bb..f278549 100644 --- a/drivers/i2c/algos/i2c-algo-sibyte.c +++ b/drivers/i2c/algos/i2c-algo-sibyte.c @@ -24,7 +24,6 @@ /* Ported for SiByte SOCs by Broadcom Corporation. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index b00cd40..f634a07 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -53,7 +53,6 @@ /* Note: we assume there can only be one ALI1535, with one SMBus interface */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 5bd6a4a..0f781a1 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -60,7 +60,6 @@ /* Note: we assume there can only be one ALI15X3, with one SMBus interface */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index eca5ed3..6347ebc 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -37,7 +37,6 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index af22b40..d664448 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -8,7 +8,6 @@ * the Free Software Foundation version 2. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index 75831a20..a7ff112 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -27,7 +27,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 0a77200..6930b66 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -25,7 +25,6 @@ /* Partialy rewriten by Oleg I. Vdovikin for mmapped support of for Alpha Processor Inc. UP-2000(+) boards */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-frodo.c b/drivers/i2c/busses/i2c-frodo.c index e093829..b6f52f5 100644 --- a/drivers/i2c/busses/i2c-frodo.c +++ b/drivers/i2c/busses/i2c-frodo.c @@ -12,7 +12,6 @@ * version 2 as published by the Free Software Foundation. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 59c238c..45e6efb1 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -41,7 +41,6 @@ /* Note: we assume there can only be one I801, with one SMBus interface */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index ef358bd..0ff7016 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -34,7 +34,6 @@ i815 1132 */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h index d819a95..2b3219d 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.h +++ b/drivers/i2c/busses/i2c-ibm_iic.h @@ -22,7 +22,6 @@ #ifndef __I2C_IBM_IIC_H_ #define __I2C_IBM_IIC_H_ -#include #include struct iic_regs { diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 0f54a2a..00e7f71 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -24,7 +24,6 @@ the SMBus and the ISA bus very much easier. See lm78.c for an example of this. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c index 702e3de..5f5d294 100644 --- a/drivers/i2c/busses/i2c-ite.c +++ b/drivers/i2c/busses/i2c-ite.c @@ -33,7 +33,6 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index 867d443..363e545 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -46,7 +46,6 @@ sound driver to be happy */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 6d13127..74eb89a 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -37,7 +37,6 @@ /* Note: we assume there can only be one nForce2, with two SMBus interfaces */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index cb5e722..3e5eba9 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -24,7 +24,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ------------------------------------------------------------------------ */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index e9560ba..112d491 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -24,7 +24,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ------------------------------------------------------------------------ */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index 9c61113..d9b4ddb 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -17,7 +17,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 646381b..1f80ba9 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -28,7 +28,6 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 13d6628..83fd16d 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c @@ -54,7 +54,6 @@ * (Additional documentation needed :( */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c index 9497b1b..0ebec3c 100644 --- a/drivers/i2c/busses/i2c-rpx.c +++ b/drivers/i2c/busses/i2c-rpx.c @@ -11,7 +11,6 @@ * changed to eliminate RPXLite references. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index fcfa51c..1e71018 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -20,6 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 092d032..0c85182 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c @@ -29,7 +29,6 @@ it easier to add later. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index e5dd90b..1c99536 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -17,7 +17,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 425733b..2b5911c 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -55,7 +55,6 @@ * Add adapter resets */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 58df63d..f58455e 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -48,7 +48,6 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 3cac6d4..6484792 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -32,7 +32,6 @@ We assume there can only be one SiS96x with one SMBus interface. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index 19c805e..00d94e8 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c @@ -21,7 +21,6 @@ #define DEBUG 1 -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 2cbc4cd..040b8ab 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -21,7 +21,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 0bb60a6..6b50080 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -33,7 +33,6 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 3edf0e3..b675773 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -27,7 +27,6 @@ /* This interfaces to the I2C bus of the Voodoo3 to gain access to the BT869 and possibly other I2C devices. */ -#include #include #include #include diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 1c4159a..a18bdd9 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -24,7 +24,6 @@ */ -#include #include #include #include diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index 9058c39..f450c0b 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -19,7 +19,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c index 111f0c8..1dd823e 100644 --- a/drivers/i2c/chips/adm1025.c +++ b/drivers/i2c/chips/adm1025.c @@ -45,7 +45,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c index b15fafe..9d2ea21 100644 --- a/drivers/i2c/chips/adm1026.c +++ b/drivers/i2c/chips/adm1026.c @@ -23,7 +23,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 36bb383..74ece8a 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -13,7 +13,6 @@ * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip */ -#include #include #include #include diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index cbdfa2d..addf0ad 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -26,7 +26,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c index c3f37db..da41174 100644 --- a/drivers/i2c/chips/fscher.c +++ b/drivers/i2c/chips/fscher.c @@ -26,7 +26,6 @@ * and Philip Edelbrock */ -#include #include #include #include diff --git a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c index 4316a15..6bedf72 100644 --- a/drivers/i2c/chips/gl518sm.c +++ b/drivers/i2c/chips/gl518sm.c @@ -36,7 +36,6 @@ * 2004-01-31 Code review and approval. (Jean Delvare) */ -#include #include #include #include diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 007bdf9..471eb42 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -31,7 +31,6 @@ type at module load time. */ -#include #include #include #include diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c index bc68e03..7bdacfd 100644 --- a/drivers/i2c/chips/lm63.c +++ b/drivers/i2c/chips/lm63.c @@ -37,7 +37,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c index 57c51ac..5be164e 100644 --- a/drivers/i2c/chips/lm75.c +++ b/drivers/i2c/chips/lm75.c @@ -18,7 +18,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/lm77.c b/drivers/i2c/chips/lm77.c index 9d15cd5..b98f449 100644 --- a/drivers/i2c/chips/lm77.c +++ b/drivers/i2c/chips/lm77.c @@ -25,7 +25,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c index 21b195f..2461992 100644 --- a/drivers/i2c/chips/lm78.c +++ b/drivers/i2c/chips/lm78.c @@ -18,7 +18,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c index 404057b..8100595 100644 --- a/drivers/i2c/chips/lm80.c +++ b/drivers/i2c/chips/lm80.c @@ -21,7 +21,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c index 4d6d7d2..de8f8ea 100644 --- a/drivers/i2c/chips/lm83.c +++ b/drivers/i2c/chips/lm83.c @@ -27,7 +27,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c index b197677..d618d10 100644 --- a/drivers/i2c/chips/lm85.c +++ b/drivers/i2c/chips/lm85.c @@ -23,7 +23,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/lm87.c b/drivers/i2c/chips/lm87.c index 4372b61..1921ed1 100644 --- a/drivers/i2c/chips/lm87.c +++ b/drivers/i2c/chips/lm87.c @@ -52,7 +52,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c index 9b127a0..d4da90d 100644 --- a/drivers/i2c/chips/lm90.c +++ b/drivers/i2c/chips/lm90.c @@ -70,7 +70,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/chips/max1619.c b/drivers/i2c/chips/max1619.c index 30a1961..bf553dc 100644 --- a/drivers/i2c/chips/max1619.c +++ b/drivers/i2c/chips/max1619.c @@ -26,7 +26,6 @@ */ -#include #include #include #include diff --git a/drivers/i2c/chips/pc87360.c b/drivers/i2c/chips/pc87360.c index 65637b2..876c68f 100644 --- a/drivers/i2c/chips/pc87360.c +++ b/drivers/i2c/chips/pc87360.c @@ -33,7 +33,6 @@ * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). */ -#include #include #include #include diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index fefc24a..65bab3a 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -30,7 +30,6 @@ Warning - only supports a single device. */ -#include #include #include #include diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index c3926d2..8912390 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -35,7 +35,6 @@ */ -#include #include #include #include diff --git a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c index 74d4b58..4469d52 100644 --- a/drivers/i2c/chips/w83l785ts.c +++ b/drivers/i2c/chips/w83l785ts.c @@ -30,7 +30,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 4cc8c9f..ecf43b1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -21,7 +21,6 @@ All SMBus-related things are written by Frodo Looijaard SMBus 2.0 support by Mark Studebaker */ -#include #include #include #include diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 86c4d01..cb217c4 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -29,7 +29,6 @@ /* The devfs code is contributed by Philipp Matthias Hahn */ -#include #include #include #include -- cgit v0.10.2 From a551ef79d9413727f76d22dc47b5b15d1d03073b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 16 Apr 2005 18:49:22 +0200 Subject: [PATCH] I2C: #include cleanup Hi Alexey, > Files that don't use CONFIG_* stuff shouldn't include config.h > Files that use CONFIG_* stuff should include config.h > > It's that simple. ;-) I agree. This won't change anything though, as all drivers include either device.h or module.h, which in turn include config.h. But you are still correct, so I approve your patch. For completeness, I would propose the following on top of your own patch: i2c bus drivers do not need to define DEBUG themselves, as the Kconfig system takes care of it. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index 21cd54d..ec943ca 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -26,11 +26,6 @@ * 'enabled' to drive the GPIOs. */ -#include -#ifdef CONFIG_I2C_DEBUG_BUS -#define DEBUG 1 -#endif - #include #include #include diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 8c55eaf..f6f5ca3 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -26,11 +26,6 @@ * that is passed as the platform_data to this driver. */ -#include -#ifdef CONFIG_I2C_DEBUG_BUS -#define DEBUG 1 -#endif - #include #include #include -- cgit v0.10.2 From 40b5cda28aafe3744d8808c21f7959e472a9ecb1 Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Sat, 30 Apr 2005 21:41:29 +1000 Subject: [PATCH] I2C: add new hardware monitor driver: adm9240 Completion of Michiel Rook's port of adm9240 to 2.6 with addition of auto fan clock divider based on Jean Delvare's algorithm, and replaces scaling macros with static inlines. Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 67be4c9..3c8863f 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -51,6 +51,17 @@ config SENSORS_ADM1031 This driver can also be built as a module. If so, the module will be called adm1031. +config SENSORS_ADM9240 + tristate "Analog Devices ADM9240 and compatibles" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM9240, + Dallas DS1780, National Semiconductor LM81 sensor chips. + + This driver can also be built as a module. If so, the module + will be called adm9240. + config SENSORS_ASB100 tristate "Asus ASB100 Bach" depends on I2C && EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 6fadd78..247fc98 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o +obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_DS1337) += ds1337.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o diff --git a/drivers/i2c/chips/adm9240.c b/drivers/i2c/chips/adm9240.c new file mode 100644 index 0000000..0b67eab --- /dev/null +++ b/drivers/i2c/chips/adm9240.c @@ -0,0 +1,768 @@ +/* + * adm9240.c Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * + * Copyright (C) 1999 Frodo Looijaard + * Philip Edelbrock + * Copyright (C) 2003 Michiel Rook + * Copyright (C) 2005 Grant Coady with valuable + * guidance from Jean Delvare + * + * Driver supports Analog Devices ADM9240 + * Dallas Semiconductor DS1780 + * National Semiconductor LM81 + * + * ADM9240 is the reference, DS1780 and LM81 are register compatibles + * + * Voltage Six inputs are scaled by chip, VID also reported + * Temperature Chip temperature to 0.5'C, maximum and max_hysteris + * Fans 2 fans, low speed alarm, automatic fan clock divider + * Alarms 16-bit map of active alarms + * Analog Out 0..1250 mV output + * + * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear' + * + * Test hardware: Intel SE440BX-2 desktop motherboard --Grant + * + * LM81 extended temp reading not implemented + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, + I2C_CLIENT_END }; + +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_3(adm9240, ds1780, lm81); + +/* ADM9240 registers */ +#define ADM9240_REG_MAN_ID 0x3e +#define ADM9240_REG_DIE_REV 0x3f +#define ADM9240_REG_CONFIG 0x40 + +#define ADM9240_REG_IN(nr) (0x20 + (nr)) /* 0..5 */ +#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define ADM9240_REG_FAN(nr) (0x28 + (nr)) /* 0..1 */ +#define ADM9240_REG_FAN_MIN(nr) (0x3b + (nr)) +#define ADM9240_REG_INT(nr) (0x41 + (nr)) +#define ADM9240_REG_INT_MASK(nr) (0x43 + (nr)) +#define ADM9240_REG_TEMP 0x27 +#define ADM9240_REG_TEMP_HIGH 0x39 +#define ADM9240_REG_TEMP_HYST 0x3a +#define ADM9240_REG_ANALOG_OUT 0x19 +#define ADM9240_REG_CHASSIS_CLEAR 0x46 +#define ADM9240_REG_VID_FAN_DIV 0x47 +#define ADM9240_REG_I2C_ADDR 0x48 +#define ADM9240_REG_VID4 0x49 +#define ADM9240_REG_TEMP_CONF 0x4b + +/* generalised scaling with integer rounding */ +static inline int SCALE(long val, int mul, int div) +{ + if (val < 0) + return (val * mul - div / 2) / div; + else + return (val * mul + div / 2) / div; +} + +/* adm9240 internally scales voltage measurements */ +static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 }; + +static inline unsigned int IN_FROM_REG(u8 reg, int n) +{ + return SCALE(reg, nom_mv[n], 192); +} + +static inline u8 IN_TO_REG(unsigned long val, int n) +{ + return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); +} + +/* temperature range: -40..125, 127 disables temperature alarm */ +static inline s8 TEMP_TO_REG(long val) +{ + return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127); +} + +/* two fans, each with low fan speed limit */ +static inline unsigned int FAN_FROM_REG(u8 reg, u8 div) +{ + if (!reg) /* error */ + return -1; + + if (reg == 255) + return 0; + + return SCALE(1350000, 1, reg * div); +} + +/* analog out 0..1250mV */ +static inline u8 AOUT_TO_REG(unsigned long val) +{ + return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255); +} + +static inline unsigned int AOUT_FROM_REG(u8 reg) +{ + return SCALE(reg, 1250, 255); +} + +static int adm9240_attach_adapter(struct i2c_adapter *adapter); +static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind); +static void adm9240_init_client(struct i2c_client *client); +static int adm9240_detach_client(struct i2c_client *client); +static struct adm9240_data *adm9240_update_device(struct device *dev); + +/* driver data */ +static struct i2c_driver adm9240_driver = { + .owner = THIS_MODULE, + .name = "adm9240", + .id = I2C_DRIVERID_ADM9240, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm9240_attach_adapter, + .detach_client = adm9240_detach_client, +}; + +/* per client data */ +struct adm9240_data { + enum chips type; + struct i2c_client client; + struct semaphore update_lock; + char valid; + unsigned long last_updated_measure; + unsigned long last_updated_config; + + u8 in[6]; /* ro in0_input */ + u8 in_max[6]; /* rw in0_max */ + u8 in_min[6]; /* rw in0_min */ + u8 fan[2]; /* ro fan1_input */ + u8 fan_min[2]; /* rw fan1_min */ + u8 fan_div[2]; /* rw fan1_div, read-only accessor */ + s16 temp; /* ro temp1_input, 9-bit sign-extended */ + s8 temp_high; /* rw temp1_max */ + s8 temp_hyst; /* rw temp1_max_hyst */ + u16 alarms; /* ro alarms */ + u8 aout; /* rw analog_out */ + u8 vid; /* ro vid */ + u8 vrm; /* -- vrm set on startup, no accessor */ +}; + +/* i2c byte read/write interface */ +static int adm9240_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/*** sysfs accessors ***/ + +/* temperature */ +#define show_temp(value, scale) \ +static ssize_t show_##value(struct device *dev, char *buf) \ +{ \ + struct adm9240_data *data = adm9240_update_device(dev); \ + return sprintf(buf, "%d\n", data->value * scale); \ +} +show_temp(temp_high, 1000); +show_temp(temp_hyst, 1000); +show_temp(temp, 500); + +#define set_temp(value, reg) \ +static ssize_t set_##value(struct device *dev, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm9240_data *data = adm9240_update_device(dev); \ + long temp = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_TO_REG(temp); \ + adm9240_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} + +set_temp(temp_high, ADM9240_REG_TEMP_HIGH); +set_temp(temp_hyst, ADM9240_REG_TEMP_HYST); + +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_temp_high, set_temp_high); +static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, + show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); + +/* voltage */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr)); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr)); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr)); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val, nr); + adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val, nr); + adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t show_in##offset(struct device *dev, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ +static ssize_t show_in##offset##_min(struct device *dev, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t show_in##offset##_max(struct device *dev, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t \ +set_in##offset##_min(struct device *dev, const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t \ +set_in##offset##_max(struct device *dev, const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); +show_in_offset(5); + +/* fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + 1 << data->fan_div[nr])); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + 1 << data->fan_div[nr])); +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", 1 << data->fan_div[nr]); +} + +/* write new fan div, callers must hold data->update_lock */ +static void adm9240_write_fan_div(struct i2c_client *client, int nr, + u8 fan_div) +{ + u8 reg, old, shift = (nr + 2) * 2; + + reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + old = (reg >> shift) & 3; + reg &= ~(3 << shift); + reg |= (fan_div << shift); + adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg); + dev_dbg(&client->dev, "fan%d clock divider changed from %u " + "to %u\n", nr + 1, 1 << old, 1 << fan_div); +} + +/* + * set fan speed low limit: + * + * - value is zero: disable fan speed low limit alarm + * + * - value is below fan speed measurement range: enable fan speed low + * limit alarm to be asserted while fan speed too slow to measure + * + * - otherwise: select fan clock divider to suit fan speed low limit, + * measurement code may adjust registers to ensure fan speed reading + */ +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + u8 new_div; + + down(&data->update_lock); + + if (!val) { + data->fan_min[nr] = 255; + new_div = data->fan_div[nr]; + + dev_dbg(&client->dev, "fan%u low limit set disabled\n", + nr + 1); + + } else if (val < 1350000 / (8 * 254)) { + new_div = 3; + data->fan_min[nr] = 254; + + dev_dbg(&client->dev, "fan%u low limit set minimum %u\n", + nr + 1, FAN_FROM_REG(254, 1 << new_div)); + + } else { + unsigned int new_min = 1350000 / val; + + new_div = 0; + while (new_min > 192 && new_div < 3) { + new_div++; + new_min /= 2; + } + if (!new_min) /* keep > 0 */ + new_min++; + + data->fan_min[nr] = new_min; + + dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n", + nr + 1, FAN_FROM_REG(new_min, 1 << new_div)); + } + + if (new_div != data->fan_div[nr]) { + data->fan_div[nr] = new_div; + adm9240_write_fan_div(client, nr, new_div); + } + adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr), + data->fan_min[nr]); + + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +{ \ +return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +{ \ +return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +{ \ +return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, \ +const char *buf, size_t count) \ +{ \ +return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan_##offset, NULL); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ + show_fan_##offset##_div, NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +show_fan_offset(1); +show_fan_offset(2); + +/* alarms */ +static ssize_t show_alarms(struct device *dev, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* vid */ +static ssize_t show_vid(struct device *dev, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +/* analog output */ +static ssize_t show_aout(struct device *dev, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); +} + +static ssize_t set_aout(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->aout = AOUT_TO_REG(val); + adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout); + up(&data->update_lock); + return count; +} +static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); + +/* chassis_clear */ +static ssize_t chassis_clear(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long val = simple_strtol(buf, NULL, 10); + + if (val == 1) { + adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); + dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); + } + return count; +} +static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear); + + +/*** sensor chip detect and driver install ***/ + +static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct adm9240_data *data; + int err = 0; + const char *name = ""; + u8 man_id, die_rev; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct adm9240_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm9240_driver; + new_client->flags = 0; + + if (kind == 0) { + kind = adm9240; + } + + if (kind < 0) { + + /* verify chip: reg address should match i2c address */ + if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR) + != address) { + dev_err(&adapter->dev, "detect fail: address match, " + "0x%02x\n", address); + goto exit_free; + } + + /* check known chip manufacturer */ + man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID); + + if (man_id == 0x23) { + kind = adm9240; + } else if (man_id == 0xda) { + kind = ds1780; + } else if (man_id == 0x01) { + kind = lm81; + } else { + dev_err(&adapter->dev, "detect fail: unknown manuf, " + "0x%02x\n", man_id); + goto exit_free; + } + + /* successful detect, print chip info */ + die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV); + dev_info(&adapter->dev, "found %s revision %u\n", + man_id == 0x23 ? "ADM9240" : + man_id == 0xda ? "DS1780" : "LM81", die_rev); + } + + /* either forced or detected chip kind */ + if (kind == adm9240) { + name = "adm9240"; + } else if (kind == ds1780) { + name = "ds1780"; + } else if (kind == lm81) { + name = "lm81"; + } + + /* fill in the remaining client fields and attach */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->type = kind; + init_MUTEX(&data->update_lock); + + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + adm9240_init_client(new_client); + + /* populate sysfs filesystem */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_aout_output); + device_create_file(&new_client->dev, &dev_attr_chassis_clear); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + + return 0; +exit_free: + kfree(new_client); +exit: + return err; +} + +static int adm9240_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, adm9240_detect); +} + +static int adm9240_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static void adm9240_init_client(struct i2c_client *client) +{ + struct adm9240_data *data = i2c_get_clientdata(client); + u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG); + u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3; + + data->vrm = i2c_which_vrm(); /* need this to report vid as mV */ + + if (conf & 1) { /* measurement cycle running: report state */ + + dev_info(&client->dev, "status: config 0x%02x mode %u\n", + conf, mode); + + } else { /* cold start: open limits before starting chip */ + int i; + + for (i = 0; i < 6; i++) + { + adm9240_write_value(client, + ADM9240_REG_IN_MIN(i), 0); + adm9240_write_value(client, + ADM9240_REG_IN_MAX(i), 255); + } + adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255); + adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255); + adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127); + adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127); + + /* start measurement cycle */ + adm9240_write_value(client, ADM9240_REG_CONFIG, 1); + + dev_info(&client->dev, "cold start: config was 0x%02x " + "mode %u\n", conf, mode); + } +} + +static struct adm9240_data *adm9240_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + /* minimum measurement cycle: 1.75 seconds */ + if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) + || !data->valid) { + + for (i = 0; i < 6; i++) /* read voltages */ + { + data->in[i] = adm9240_read_value(client, + ADM9240_REG_IN(i)); + } + data->alarms = adm9240_read_value(client, + ADM9240_REG_INT(0)) | + adm9240_read_value(client, + ADM9240_REG_INT(1)) << 8; + + /* read temperature: assume temperature changes less than + * 0.5'C per two measurement cycles thus ignore possible + * but unlikely aliasing error on lsb reading. --Grant */ + data->temp = ((adm9240_read_value(client, + ADM9240_REG_TEMP) << 8) | + adm9240_read_value(client, + ADM9240_REG_TEMP_CONF)) / 128; + + for (i = 0; i < 2; i++) /* read fans */ + { + data->fan[i] = adm9240_read_value(client, + ADM9240_REG_FAN(i)); + + /* adjust fan clock divider on overflow */ + if (data->valid && data->fan[i] == 255 && + data->fan_div[i] < 3) { + + adm9240_write_fan_div(client, i, + ++data->fan_div[i]); + + /* adjust fan_min if active, but not to 0 */ + if (data->fan_min[i] < 255 && + data->fan_min[i] >= 2) + data->fan_min[i] /= 2; + } + } + data->last_updated_measure = jiffies; + } + + /* minimum config reading cycle: 300 seconds */ + if (time_after(jiffies, data->last_updated_config + (HZ * 300)) + || !data->valid) { + + for (i = 0; i < 6; i++) + { + data->in_min[i] = adm9240_read_value(client, + ADM9240_REG_IN_MIN(i)); + data->in_max[i] = adm9240_read_value(client, + ADM9240_REG_IN_MAX(i)); + } + for (i = 0; i < 2; i++) + { + data->fan_min[i] = adm9240_read_value(client, + ADM9240_REG_FAN_MIN(i)); + } + data->temp_high = adm9240_read_value(client, + ADM9240_REG_TEMP_HIGH); + data->temp_hyst = adm9240_read_value(client, + ADM9240_REG_TEMP_HYST); + + /* read fan divs and 5-bit VID */ + i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + data->fan_div[0] = (i >> 4) & 3; + data->fan_div[1] = (i >> 6) & 3; + data->vid = i & 0x0f; + data->vid |= (adm9240_read_value(client, + ADM9240_REG_VID4) & 1) << 4; + /* read analog out */ + data->aout = adm9240_read_value(client, + ADM9240_REG_ANALOG_OUT); + + data->last_updated_config = jiffies; + data->valid = 1; + } + up(&data->update_lock); + return data; +} + +static int __init sensors_adm9240_init(void) +{ + return i2c_add_driver(&adm9240_driver); +} + +static void __exit sensors_adm9240_exit(void) +{ + i2c_del_driver(&adm9240_driver); +} + +MODULE_AUTHOR("Michiel Rook , " + "Grant Coady and others"); +MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_adm9240_init); +module_exit(sensors_adm9240_exit); + -- cgit v0.10.2 From 08e7e2789e0da49eadeb17121e24af22efeee84b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 25 Apr 2005 22:43:25 +0200 Subject: [PATCH] I2C: New hardware monitoring driver: w83627ehf This is a new hardware monitoring driver, w83627ehf, which supports the Winbond W83627EHF Super-I/O chip. The driver is not complete, but already usable. It only implements fan speed and temperature monitoring, while the chip also supports voltage inputs with VID, PWM output and temperature sensor selection. I have no more time to work on this, but anyone with supported hardware could add the missing functionalities later. This driver is largely derived from the w83627hf driver. Thanks to Leon Moonen and Steve Cliffe for tesing the preliminary versions of my driver and reporting the problems they encountered. Thanks to Grant Coady for noticing and fixing various corner cases in the fan management. This third version of the driver hopefully addresses all the issues the original version had. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 3c8863f..ec52e3a 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -384,6 +384,20 @@ config SENSORS_W83627HF This driver can also be built as a module. If so, the module will be called w83627hf. +config SENSORS_W83627EHF + tristate "Winbond W83627EHF" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get preliminary support for the hardware + monitoring functionality of the Winbond W83627EHF Super-I/O chip. + Only fan and temperature inputs are supported at the moment, while + the chip does much more than that. + + This driver can also be built as a module. If so, the module + will be called w83627ehf. + endmenu menu "Other I2C Chip support" diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 247fc98..2281435 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o +obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o diff --git a/drivers/i2c/chips/w83627ehf.c b/drivers/i2c/chips/w83627ehf.c new file mode 100644 index 0000000..7bb693d --- /dev/null +++ b/drivers/i2c/chips/w83627ehf.c @@ -0,0 +1,839 @@ +/* + w83627ehf - Driver for the hardware monitoring functionality of + the Winbond W83627EHF Super-I/O chip + Copyright (C) 2005 Jean Delvare + + Shamelessly ripped from the w83627hf driver + Copyright (C) 2003 Mark Studebaker + + Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help + in testing and debugging this driver. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + + Supports the following chips: + + Chip #vin #fan #pwm #temp chip_id man_id + w83627ehf - 5 - 3 0x88 0x5ca3 + + This is a preliminary version of the driver, only supporting the + fan and temperature inputs. The chip does much more than that. +*/ + +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +/* Addresses to scan + The actual ISA address is read from Super-I/O configuration space */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(w83627ehf); + +/* + * Super-I/O constants and functions + */ + +static int REG; /* The register to read/write */ +static int VAL; /* The value to read/write */ + +#define W83627EHF_LD_HWM 0x0b + +#define SIO_REG_LDSEL 0x07 /* Logical device select */ +#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_REG_ENABLE 0x30 /* Logical device enable */ +#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ + +#define SIO_W83627EHF_ID 0x8840 +#define SIO_ID_MASK 0xFFC0 + +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static inline void +superio_select(int ld) +{ + outb(SIO_REG_LDSEL, REG); + outb(ld, VAL); +} + +static inline void +superio_enter(void) +{ + outb(0x87, REG); + outb(0x87, REG); +} + +static inline void +superio_exit(void) +{ + outb(0x02, REG); + outb(0x02, VAL); +} + +/* + * ISA constants + */ + +#define REGION_LENGTH 8 +#define ADDR_REG_OFFSET 5 +#define DATA_REG_OFFSET 6 + +#define W83627EHF_REG_BANK 0x4E +#define W83627EHF_REG_CONFIG 0x40 +#define W83627EHF_REG_CHIP_ID 0x49 +#define W83627EHF_REG_MAN_ID 0x4F + +static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; +static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; + +#define W83627EHF_REG_TEMP1 0x27 +#define W83627EHF_REG_TEMP1_HYST 0x3a +#define W83627EHF_REG_TEMP1_OVER 0x39 +static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 }; +static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 }; +static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 }; +static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; + +/* Fan clock dividers are spread over the following five registers */ +#define W83627EHF_REG_FANDIV1 0x47 +#define W83627EHF_REG_FANDIV2 0x4B +#define W83627EHF_REG_VBAT 0x5D +#define W83627EHF_REG_DIODE 0x59 +#define W83627EHF_REG_SMI_OVT 0x4C + +/* + * Conversions + */ + +static inline unsigned int +fan_from_reg(u8 reg, unsigned int div) +{ + if (reg == 0 || reg == 255) + return 0; + return 1350000U / (reg * div); +} + +static inline unsigned int +div_from_reg(u8 reg) +{ + return 1 << reg; +} + +static inline int +temp1_from_reg(s8 reg) +{ + return reg * 1000; +} + +static inline s8 +temp1_to_reg(int temp) +{ + if (temp <= -128000) + return -128; + if (temp >= 127000) + return 127; + if (temp < 0) + return (temp - 500) / 1000; + return (temp + 500) / 1000; +} + +/* + * Data structures and manipulation thereof + */ + +struct w83627ehf_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + /* Register values */ + u8 fan[5]; + u8 fan_min[5]; + u8 fan_div[5]; + u8 has_fan; /* some fan inputs can be disabled */ + s8 temp1; + s8 temp1_max; + s8 temp1_max_hyst; + s16 temp[2]; + s16 temp_max[2]; + s16 temp_max_hyst[2]; +}; + +static inline int is_word_sized(u16 reg) +{ + return (((reg & 0xff00) == 0x100 + || (reg & 0xff00) == 0x200) + && ((reg & 0x00ff) == 0x50 + || (reg & 0x00ff) == 0x53 + || (reg & 0x00ff) == 0x55)); +} + +/* We assume that the default bank is 0, thus the following two functions do + nothing for registers which live in bank 0. For others, they respectively + set the bank register to the correct value (before the register is + accessed), and back to 0 (afterwards). */ +static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); + outb_p(reg >> 8, client->addr + DATA_REG_OFFSET); + } +} + +static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); + outb_p(0, client->addr + DATA_REG_OFFSET); + } +} + +static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int res, word_sized = is_word_sized(reg); + + down(&data->lock); + + w83627ehf_set_bank(client, reg); + outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); + res = inb_p(client->addr + DATA_REG_OFFSET); + if (word_sized) { + outb_p((reg & 0xff) + 1, + client->addr + ADDR_REG_OFFSET); + res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET); + } + w83627ehf_reset_bank(client, reg); + + up(&data->lock); + + return res; +} + +static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int word_sized = is_word_sized(reg); + + down(&data->lock); + + w83627ehf_set_bank(client, reg); + outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); + if (word_sized) { + outb_p(value >> 8, client->addr + DATA_REG_OFFSET); + outb_p((reg & 0xff) + 1, + client->addr + ADDR_REG_OFFSET); + } + outb_p(value & 0xff, client->addr + DATA_REG_OFFSET); + w83627ehf_reset_bank(client, reg); + + up(&data->lock); + return 0; +} + +/* This function assumes that the caller holds data->update_lock */ +static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + u8 reg; + + switch (nr) { + case 0: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf) + | ((data->fan_div[0] & 0x03) << 4); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf) + | ((data->fan_div[0] & 0x04) << 3); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 1: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f) + | ((data->fan_div[1] & 0x03) << 6); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf) + | ((data->fan_div[1] & 0x04) << 4); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 2: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f) + | ((data->fan_div[2] & 0x03) << 6); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f) + | ((data->fan_div[2] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 3: + reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc) + | (data->fan_div[3] & 0x03); + w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f) + | ((data->fan_div[3] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg); + break; + case 4: + reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73) + | ((data->fan_div[4] & 0x03) << 3) + | ((data->fan_div[4] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); + break; + } +} + +static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) + || !data->valid) { + /* Fan clock dividers */ + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2); + data->fan_div[2] = (i >> 6) & 0x03; + i = w83627ehf_read_value(client, W83627EHF_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + data->fan_div[2] |= (i >> 5) & 0x04; + if (data->has_fan & ((1 << 3) | (1 << 4))) { + i = w83627ehf_read_value(client, W83627EHF_REG_DIODE); + data->fan_div[3] = i & 0x03; + data->fan_div[4] = ((i >> 2) & 0x03) + | ((i >> 5) & 0x04); + } + if (data->has_fan & (1 << 3)) { + i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT); + data->fan_div[3] |= (i >> 5) & 0x04; + } + + /* Measured fan speeds and limits */ + for (i = 0; i < 5; i++) { + if (!(data->has_fan & (1 << i))) + continue; + + data->fan[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN[i]); + data->fan_min[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN_MIN[i]); + + /* If we failed to measure the fan speed and clock + divider can be increased, let's try that for next + time */ + if (data->fan[i] == 0xff + && data->fan_div[i] < 0x07) { + dev_dbg(&client->dev, "Increasing fan %d " + "clock divider from %u to %u\n", + i, div_from_reg(data->fan_div[i]), + div_from_reg(data->fan_div[i] + 1)); + data->fan_div[i]++; + w83627ehf_write_fan_div(client, i); + /* Preserve min limit if possible */ + if (data->fan_min[i] >= 2 + && data->fan_min[i] != 255) + w83627ehf_write_value(client, + W83627EHF_REG_FAN_MIN[i], + (data->fan_min[i] /= 2)); + } + } + + /* Measured temperatures and limits */ + data->temp1 = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1); + data->temp1_max = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1_OVER); + data->temp1_max_hyst = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1_HYST); + for (i = 0; i < 2; i++) { + data->temp[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP[i]); + data->temp_max[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_OVER[i]); + data->temp_max_hyst[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_HYST[i]); + } + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + return data; +} + +/* + * Sysfs callback functions + */ + +#define show_fan_reg(reg) \ +static ssize_t \ +show_##reg(struct device *dev, char *buf, int nr) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", \ + fan_from_reg(data->reg[nr], \ + div_from_reg(data->fan_div[nr]))); \ +} +show_fan_reg(fan); +show_fan_reg(fan_min); + +static ssize_t +show_fan_div(struct device *dev, char *buf, int nr) +{ + struct w83627ehf_data *data = w83627ehf_update_device(dev); + return sprintf(buf, "%u\n", + div_from_reg(data->fan_div[nr])); +} + +static ssize_t +store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + unsigned int val = simple_strtoul(buf, NULL, 10); + unsigned int reg; + u8 new_div; + + down(&data->update_lock); + if (!val) { + /* No min limit, alarm disabled */ + data->fan_min[nr] = 255; + new_div = data->fan_div[nr]; /* No change */ + dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1); + } else if ((reg = 1350000U / val) >= 128 * 255) { + /* Speed below this value cannot possibly be represented, + even with the highest divider (128) */ + data->fan_min[nr] = 254; + new_div = 7; /* 128 == (1 << 7) */ + dev_warn(dev, "fan%u low limit %u below minimum %u, set to " + "minimum\n", nr + 1, val, fan_from_reg(254, 128)); + } else if (!reg) { + /* Speed above this value cannot possibly be represented, + even with the lowest divider (1) */ + data->fan_min[nr] = 1; + new_div = 0; /* 1 == (1 << 0) */ + dev_warn(dev, "fan%u low limit %u above maximum %u, set to " + "maximum\n", nr + 1, val, fan_from_reg(1, 0)); + } else { + /* Automatically pick the best divider, i.e. the one such + that the min limit will correspond to a register value + in the 96..192 range */ + new_div = 0; + while (reg > 192 && new_div < 7) { + reg >>= 1; + new_div++; + } + data->fan_min[nr] = reg; + } + + /* Write both the fan clock divider (if it changed) and the new + fan min (unconditionally) */ + if (new_div != data->fan_div[nr]) { + if (new_div > data->fan_div[nr]) + data->fan[nr] >>= (data->fan_div[nr] - new_div); + else + data->fan[nr] <<= (new_div - data->fan_div[nr]); + + dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", + nr + 1, div_from_reg(data->fan_div[nr]), + div_from_reg(new_div)); + data->fan_div[nr] = new_div; + w83627ehf_write_fan_div(client, nr); + } + w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr], + data->fan_min[nr]); + up(&data->update_lock); + + return count; +} + +#define sysfs_fan_offset(offset) \ +static ssize_t \ +show_reg_fan_##offset(struct device *dev, char *buf) \ +{ \ + return show_fan(dev, buf, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_reg_fan_##offset, NULL); + +#define sysfs_fan_min_offset(offset) \ +static ssize_t \ +show_reg_fan##offset##_min(struct device *dev, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset-1); \ +} \ +static ssize_t \ +store_reg_fan##offset##_min(struct device *dev, const char *buf, \ + size_t count) \ +{ \ + return store_fan_min(dev, buf, count, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_reg_fan##offset##_min, \ + store_reg_fan##offset##_min); + +#define sysfs_fan_div_offset(offset) \ +static ssize_t \ +show_reg_fan##offset##_div(struct device *dev, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ + show_reg_fan##offset##_div, NULL); + +sysfs_fan_offset(1); +sysfs_fan_min_offset(1); +sysfs_fan_div_offset(1); +sysfs_fan_offset(2); +sysfs_fan_min_offset(2); +sysfs_fan_div_offset(2); +sysfs_fan_offset(3); +sysfs_fan_min_offset(3); +sysfs_fan_div_offset(3); +sysfs_fan_offset(4); +sysfs_fan_min_offset(4); +sysfs_fan_div_offset(4); +sysfs_fan_offset(5); +sysfs_fan_min_offset(5); +sysfs_fan_div_offset(5); + +#define show_temp1_reg(reg) \ +static ssize_t \ +show_##reg(struct device *dev, char *buf) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \ +} +show_temp1_reg(temp1); +show_temp1_reg(temp1_max); +show_temp1_reg(temp1_max_hyst); + +#define store_temp1_reg(REG, reg) \ +static ssize_t \ +store_temp1_##reg(struct device *dev, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + u32 val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp1_##reg = temp1_to_reg(val); \ + w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ + data->temp1_##reg); \ + up(&data->update_lock); \ + return count; \ +} +store_temp1_reg(OVER, max); +store_temp1_reg(HYST, max_hyst); + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR, + show_temp1_max, store_temp1_max); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR, + show_temp1_max_hyst, store_temp1_max_hyst); + +#define show_temp_reg(reg) \ +static ssize_t \ +show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", \ + LM75_TEMP_FROM_REG(data->reg[nr])); \ +} +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_max_hyst); + +#define store_temp_reg(REG, reg) \ +static ssize_t \ +store_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + u32 val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->reg[nr] = LM75_TEMP_TO_REG(val); \ + w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \ + data->reg[nr]); \ + up(&data->update_lock); \ + return count; \ +} +store_temp_reg(OVER, temp_max); +store_temp_reg(HYST, temp_max_hyst); + +#define sysfs_temp_offset(offset) \ +static ssize_t \ +show_reg_temp##offset (struct device *dev, char *buf) \ +{ \ + return show_temp(dev, buf, offset - 2); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_reg_temp##offset, NULL); + +#define sysfs_temp_reg_offset(reg, offset) \ +static ssize_t \ +show_reg_temp##offset##_##reg(struct device *dev, char *buf) \ +{ \ + return show_temp_##reg(dev, buf, offset - 2); \ +} \ +static ssize_t \ +store_reg_temp##offset##_##reg(struct device *dev, const char *buf, \ + size_t count) \ +{ \ + return store_temp_##reg(dev, buf, count, offset - 2); \ +} \ +static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ + show_reg_temp##offset##_##reg, \ + store_reg_temp##offset##_##reg); + +sysfs_temp_offset(2); +sysfs_temp_reg_offset(max, 2); +sysfs_temp_reg_offset(max_hyst, 2); +sysfs_temp_offset(3); +sysfs_temp_reg_offset(max, 3); +sysfs_temp_reg_offset(max_hyst, 3); + +/* + * Driver and client management + */ + +static struct i2c_driver w83627ehf_driver; + +static void w83627ehf_init_client(struct i2c_client *client) +{ + int i; + u8 tmp; + + /* Start monitoring is needed */ + tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG); + if (!(tmp & 0x01)) + w83627ehf_write_value(client, W83627EHF_REG_CONFIG, + tmp | 0x01); + + /* Enable temp2 and temp3 if needed */ + for (i = 0; i < 2; i++) { + tmp = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_CONFIG[i]); + if (tmp & 0x01) + w83627ehf_write_value(client, + W83627EHF_REG_TEMP_CONFIG[i], + tmp & 0xfe); + } +} + +static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct w83627ehf_data *data; + int i, err = 0; + + if (!i2c_is_isa_adapter(adapter)) + return 0; + + if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) { + err = -EBUSY; + goto exit; + } + + if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release; + } + memset(data, 0, sizeof(struct w83627ehf_data)); + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + init_MUTEX(&data->lock); + client->adapter = adapter; + client->driver = &w83627ehf_driver; + client->flags = 0; + + strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the i2c layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto exit_free; + + /* Initialize the chip */ + w83627ehf_init_client(client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 5; i++) + data->fan_min[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN_MIN[i]); + + /* It looks like fan4 and fan5 pins can be alternatively used + as fan on/off switches */ + data->has_fan = 0x07; /* fan1, fan2 and fan3 */ + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); + if (i & (1 << 2)) + data->has_fan |= (1 << 3); + if (i & (1 << 0)) + data->has_fan |= (1 << 4); + + /* Register sysfs hooks */ + device_create_file(&client->dev, &dev_attr_fan1_input); + device_create_file(&client->dev, &dev_attr_fan1_min); + device_create_file(&client->dev, &dev_attr_fan1_div); + device_create_file(&client->dev, &dev_attr_fan2_input); + device_create_file(&client->dev, &dev_attr_fan2_min); + device_create_file(&client->dev, &dev_attr_fan2_div); + device_create_file(&client->dev, &dev_attr_fan3_input); + device_create_file(&client->dev, &dev_attr_fan3_min); + device_create_file(&client->dev, &dev_attr_fan3_div); + + if (data->has_fan & (1 << 3)) { + device_create_file(&client->dev, &dev_attr_fan4_input); + device_create_file(&client->dev, &dev_attr_fan4_min); + device_create_file(&client->dev, &dev_attr_fan4_div); + } + if (data->has_fan & (1 << 4)) { + device_create_file(&client->dev, &dev_attr_fan5_input); + device_create_file(&client->dev, &dev_attr_fan5_min); + device_create_file(&client->dev, &dev_attr_fan5_div); + } + + device_create_file(&client->dev, &dev_attr_temp1_input); + device_create_file(&client->dev, &dev_attr_temp1_max); + device_create_file(&client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&client->dev, &dev_attr_temp2_input); + device_create_file(&client->dev, &dev_attr_temp2_max); + device_create_file(&client->dev, &dev_attr_temp2_max_hyst); + device_create_file(&client->dev, &dev_attr_temp3_input); + device_create_file(&client->dev, &dev_attr_temp3_max); + device_create_file(&client->dev, &dev_attr_temp3_max_hyst); + + return 0; + +exit_free: + kfree(data); +exit_release: + release_region(address, REGION_LENGTH); +exit: + return err; +} + +static int w83627ehf_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, w83627ehf_detect); +} + +static int w83627ehf_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + release_region(client->addr, REGION_LENGTH); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static struct i2c_driver w83627ehf_driver = { + .owner = THIS_MODULE, + .name = "w83627ehf", + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83627ehf_attach_adapter, + .detach_client = w83627ehf_detach_client, +}; + +static int __init w83627ehf_find(int sioaddr, int *address) +{ + u16 val; + + REG = sioaddr; + VAL = sioaddr + 1; + superio_enter(); + + val = (superio_inb(SIO_REG_DEVID) << 8) + | superio_inb(SIO_REG_DEVID + 1); + if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) { + superio_exit(); + return -ENODEV; + } + + superio_select(W83627EHF_LD_HWM); + val = (superio_inb(SIO_REG_ADDR) << 8) + | superio_inb(SIO_REG_ADDR + 1); + *address = val & ~(REGION_LENGTH - 1); + if (*address == 0) { + superio_exit(); + return -ENODEV; + } + + /* Activate logical device if needed */ + val = superio_inb(SIO_REG_ENABLE); + if (!(val & 0x01)) + superio_outb(SIO_REG_ENABLE, val | 0x01); + + superio_exit(); + return 0; +} + +static int __init sensors_w83627ehf_init(void) +{ + if (w83627ehf_find(0x2e, &normal_isa[0]) + && w83627ehf_find(0x4e, &normal_isa[0])) + return -ENODEV; + + return i2c_add_driver(&w83627ehf_driver); +} + +static void __exit sensors_w83627ehf_exit(void) +{ + i2c_del_driver(&w83627ehf_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("W83627EHF driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83627ehf_init); +module_exit(sensors_w83627ehf_exit); -- cgit v0.10.2 From b9110b1c893f45ec66ae39e359decdfad84525be Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 2 May 2005 23:08:22 +0200 Subject: [PATCH] I2C: Fix bugs in the new w83627ehf driver These are the fixes for the bug you spotted in my new w83627ehf driver: - Explicit division by 0. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/w83627ehf.c b/drivers/i2c/chips/w83627ehf.c index 7bb693d..4fcc823 100644 --- a/drivers/i2c/chips/w83627ehf.c +++ b/drivers/i2c/chips/w83627ehf.c @@ -450,7 +450,7 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr) data->fan_min[nr] = 1; new_div = 0; /* 1 == (1 << 0) */ dev_warn(dev, "fan%u low limit %u above maximum %u, set to " - "maximum\n", nr + 1, val, fan_from_reg(1, 0)); + "maximum\n", nr + 1, val, fan_from_reg(1, 1)); } else { /* Automatically pick the best divider, i.e. the one such that the min limit will correspond to a register value -- cgit v0.10.2 From ec5ce552d946a55c1e504054627c9068fb7afb8a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 26 Apr 2005 22:09:43 +0200 Subject: [PATCH] I2C: Add support for the LPC47M15x and LPC47M192 chips to smsc47m1 This simple patch adds support for the SMSC LPC47M15x and LPC47M192 chips to the smsc47m1 hardware monitoring driver. These chips are compatible with the other ones already supported by the driver, so I see no reason not to support them, especially when the Linux 2.4 version of the driver does already. I also modified the info printks to name the chips by their real name. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index ec52e3a..fa5730a 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -331,7 +331,7 @@ config SENSORS_SMSC47M1 help If you say yes here you get support for the integrated fan monitoring and control capabilities of the SMSC LPC47B27x, - LPC47M10x, LPC47M13x and LPC47M14x chips. + LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips. This driver can also be built as a module. If so, the module will be called smsc47m1. diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c index 13d6d4a..897117a 100644 --- a/drivers/i2c/chips/smsc47m1.c +++ b/drivers/i2c/chips/smsc47m1.c @@ -372,14 +372,16 @@ static int smsc47m1_find(int *address) * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id * 0x5F) and LPC47B27x (device id 0x51) have fan control. * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" - * can do much more besides (device id 0x60, unsupported). + * can do much more besides (device id 0x60). */ if (val == 0x51) - printk(KERN_INFO "smsc47m1: Found SMSC47B27x\n"); + printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); else if (val == 0x59) - printk(KERN_INFO "smsc47m1: Found SMSC47M10x/SMSC47M13x\n"); + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n"); else if (val == 0x5F) - printk(KERN_INFO "smsc47m1: Found SMSC47M14x\n"); + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); + else if (val == 0x60) + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n"); else { superio_exit(); return -ENODEV; -- cgit v0.10.2 From 44bbe87e9017efa050bb1b506c6822f1f3bb94d7 Mon Sep 17 00:00:00 2001 From: Steven Cole Date: Tue, 3 May 2005 18:21:25 -0600 Subject: [PATCH] Spelling fixes for drivers/i2c. Here are some spelling corrections for drivers/i2c. occured -> occurred intialization -> initialization Everytime -> Every time transfering -> transferring relevent -> relevant continous -> continuous neccessary -> necessary explicitely -> explicitly Celcius -> Celsius differenciate -> differentiate Signed-off-by: Steven Cole Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index c3d912c..dfa77eb 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -49,7 +49,7 @@ static int i2c_debug=0; /* * Generate a start condition on the i2c bus. * - * returns after the start condition has occured + * returns after the start condition has occurred */ static void pca_start(struct i2c_algo_pca_data *adap) { @@ -64,7 +64,7 @@ static void pca_start(struct i2c_algo_pca_data *adap) /* * Generate a repeated start condition on the i2c bus * - * return after the repeated start condition has occured + * return after the repeated start condition has occurred */ static void pca_repeated_start(struct i2c_algo_pca_data *adap) { diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index bb88521..93ca36d 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -695,7 +695,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ dev->irq = iic_force_poll ? -1 : ocp->def->irq; if (dev->irq >= 0){ - /* Disable interrupts until we finish intialization, + /* Disable interrupts until we finish initialization, assumes level-sensitive IRQ setup... */ iic_interrupt_mode(dev, 0); diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index c961ba4..6b682e9 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -85,7 +85,7 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE; /* - * Everytime unit enable is asserted, GPOD needs to be cleared + * Every time unit enable is asserted, GPOD needs to be cleared * on IOP321 to avoid data corruption on the bus. */ #ifdef CONFIG_ARCH_IOP321 diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 1e71018..a3b3825 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -534,7 +534,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int /* s3c24xx_i2c_xfer * * first port of call from the i2c bus code when an message needs - * transfering across the i2c bus. + * transferring across the i2c bus. */ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, diff --git a/drivers/i2c/chips/adm1031.c b/drivers/i2c/chips/adm1031.c index 2163dba..9168e98 100644 --- a/drivers/i2c/chips/adm1031.c +++ b/drivers/i2c/chips/adm1031.c @@ -440,7 +440,7 @@ pwm_reg(2); /* * That function checks the cases where the fan reading is not - * relevent. It is used to provide 0 as fan reading when the fan is + * relevant. It is used to provide 0 as fan reading when the fan is * not supposed to run */ static int trust_fan_readings(struct adm1031_data *data, int chan) diff --git a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c index 4ae15bd..5360d58 100644 --- a/drivers/i2c/chips/ds1621.c +++ b/drivers/i2c/chips/ds1621.c @@ -121,7 +121,7 @@ static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) static void ds1621_init_client(struct i2c_client *client) { int reg = ds1621_read_value(client, DS1621_REG_CONF); - /* switch to continous conversion mode */ + /* switch to continuous conversion mode */ reg &= ~ DS1621_REG_CONFIG_1SHOT; /* setup output polarity */ @@ -303,7 +303,7 @@ static struct ds1621_data *ds1621_update_client(struct device *dev) data->temp_max = ds1621_read_value(client, DS1621_REG_TEMP_MAX); - /* reset alarms if neccessary */ + /* reset alarms if necessary */ new_conf = data->conf; if (data->temp < data->temp_min) new_conf &= ~DS1621_ALARM_TEMP_LOW; diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 471eb42..16dbfd8 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -953,7 +953,7 @@ static int it87_detach_client(struct i2c_client *client) return 0; } -/* The SMBus locks itself, but ISA access must be locked explicitely! +/* The SMBus locks itself, but ISA access must be locked explicitly! We don't want to lock the whole ISA bus, so we lock each client separately. We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, @@ -973,7 +973,7 @@ static int it87_read_value(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -/* The SMBus locks itself, but ISA access muse be locked explicitely! +/* The SMBus locks itself, but ISA access muse be locked explicitly! We don't want to lock the whole ISA bus, so we lock each client separately. We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c index 7bdacfd..18b2876 100644 --- a/drivers/i2c/chips/lm63.c +++ b/drivers/i2c/chips/lm63.c @@ -98,9 +98,9 @@ SENSORS_INSMOD_1(lm63); * Conversions and various macros * For tachometer counts, the LM63 uses 16-bit values. * For local temperature and high limit, remote critical limit and hysteresis - * value, it uses signed 8-bit values with LSB = 1 degree Celcius. + * value, it uses signed 8-bit values with LSB = 1 degree Celsius. * For remote temperature, low and high limits, it uses signed 11-bit values - * with LSB = 0.125 degree Celcius, left-justified in 16-bit registers. + * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. */ #define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c index 2461992..2924146 100644 --- a/drivers/i2c/chips/lm78.c +++ b/drivers/i2c/chips/lm78.c @@ -670,7 +670,7 @@ static int lm78_detach_client(struct i2c_client *client) return 0; } -/* The SMBus locks itself, but ISA access must be locked explicitely! +/* The SMBus locks itself, but ISA access must be locked explicitly! We don't want to lock the whole ISA bus, so we lock each client separately. We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, @@ -689,7 +689,7 @@ static int lm78_read_value(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -/* The SMBus locks itself, but ISA access muse be locked explicitely! +/* The SMBus locks itself, but ISA access muse be locked explicitly! We don't want to lock the whole ISA bus, so we lock each client separately. We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c index de8f8ea..442dc17 100644 --- a/drivers/i2c/chips/lm83.c +++ b/drivers/i2c/chips/lm83.c @@ -80,7 +80,7 @@ SENSORS_INSMOD_1(lm83); /* * Conversions and various macros - * The LM83 uses signed 8-bit values with LSB = 1 degree Celcius. + * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius. */ #define TEMP_FROM_REG(val) ((val) * 1000) diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c index d4da90d..42795b4 100644 --- a/drivers/i2c/chips/lm90.c +++ b/drivers/i2c/chips/lm90.c @@ -19,7 +19,7 @@ * Complete datasheets can be obtained from National's website at: * http://www.national.com/pf/LM/LM89.html * http://www.national.com/pf/LM/LM99.html - * Note that there is no way to differenciate between both chips. + * Note that there is no way to differentiate between both chips. * * This driver also supports the LM86, another sensor chip made by * National Semiconductor. It is exactly similar to the LM90 except it @@ -39,7 +39,7 @@ * chips made by Maxim. These chips are similar to the LM86. Complete * datasheet can be obtained at Maxim's website at: * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - * Note that there is no easy way to differenciate between the three + * Note that there is no easy way to differentiate between the three * variants. The extra address and features of the MAX6659 are not * supported by this driver. * @@ -138,9 +138,9 @@ SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461); /* * Conversions and various macros * For local temperatures and limits, critical limits and the hysteresis - * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celcius. + * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. * For remote temperatures and limits, it uses signed 11-bit values with - * LSB = 0.125 degree Celcius, left-justified in 16-bit registers. + * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. */ #define TEMP1_FROM_REG(val) ((val) * 1000) -- cgit v0.10.2 From 30aedcb33970367e50b5edf373e9cd1a5cebcbe1 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 3 May 2005 18:50:38 -0500 Subject: [PATCH] I2C: Allow for sharing of the interrupt line for i2c-mpc.c I2C-MPC: Allow for sharing of the interrupt line On the MPC8548 devices we have multiple I2C-MPC buses however they are on the same interrupt line. Made request_irq pass SA_SHIRQ now so the second bus can register for the same IRQ. Signed-off-by: Kumar Gala Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 6f33496..c8a8703 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -325,7 +325,7 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) if (i2c->irq != OCP_IRQ_NA) { if ((result = request_irq(ocp->def->irq, mpc_i2c_isr, - 0, "i2c-mpc", i2c)) < 0) { + SA_SHIRQ, "i2c-mpc", i2c)) < 0) { printk(KERN_ERR "i2c-mpc - failed to attach interrupt\n"); goto fail_irq; @@ -424,7 +424,7 @@ static int fsl_i2c_probe(struct device *device) if (i2c->irq != 0) if ((result = request_irq(i2c->irq, mpc_i2c_isr, - 0, "fsl-i2c", i2c)) < 0) { + SA_SHIRQ, "i2c-mpc", i2c)) < 0) { printk(KERN_ERR "i2c-mpc - failed to attach interrupt\n"); goto fail_irq; -- cgit v0.10.2 From 815f55f280fb2781ba1c2a350516b73e55119c60 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 7 May 2005 22:58:46 +0200 Subject: [PATCH] I2C: Remove redundancy from i2c-core.c Call i2c_transfer() from i2c_master_send() and i2c_master_recv() to avoid the redundant code that was in all three functions. It also removes unnecessary debug statements as suggested by Jean Delvare. This is important for the non-blocking interfaces because they will have to handle a non-blocking interface in this area. Having it in one place greatly simplifies the changes. Signed-off-by: Corey Minyard Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index ecf43b1..f503428 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -611,27 +611,16 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count) struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; - if (client->adapter->algo->master_xfer) { - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.len = count; - msg.buf = (char *)buf; + msg.addr = client->addr; + msg.flags = client->flags & I2C_M_TEN; + msg.len = count; + msg.buf = (char *)buf; - dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", - count); - - down(&adap->bus_lock); - ret = adap->algo->master_xfer(adap,&msg,1); - up(&adap->bus_lock); + ret = i2c_transfer(adap, &msg, 1); - /* if everything went ok (i.e. 1 msg transmitted), return #bytes - * transmitted, else error code. - */ - return (ret == 1 )? count : ret; - } else { - dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); - return -ENOSYS; - } + /* If everything went ok (i.e. 1 msg transmitted), return #bytes + transmitted, else error code. */ + return (ret == 1) ? count : ret; } int i2c_master_recv(struct i2c_client *client, char *buf ,int count) @@ -639,31 +628,18 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count) struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; int ret; - if (client->adapter->algo->master_xfer) { - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.flags |= I2C_M_RD; - msg.len = count; - msg.buf = buf; - - dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n", - count); - - down(&adap->bus_lock); - ret = adap->algo->master_xfer(adap,&msg,1); - up(&adap->bus_lock); - - dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n", - ret, count, client->addr); - - /* if everything went ok (i.e. 1 msg transmitted), return #bytes - * transmitted, else error code. - */ - return (ret == 1 )? count : ret; - } else { - dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); - return -ENOSYS; - } + + msg.addr = client->addr; + msg.flags = client->flags & I2C_M_TEN; + msg.flags |= I2C_M_RD; + msg.len = count; + msg.buf = buf; + + ret = i2c_transfer(adap, &msg, 1); + + /* If everything went ok (i.e. 1 msg transmitted), return #bytes + transmitted, else error code. */ + return (ret == 1) ? count : ret; } -- cgit v0.10.2 From b9826b3ee8faa468a26782e3bf37716a73d96730 Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Fri, 6 May 2005 17:40:51 +1000 Subject: [PATCH] I2C: remove from via686a In my cross-reference checking of sysfs names, the via686a needs special case treatment as it the only driver expands S_IWUSR to 00200 with gcc -E. (00200 is the correct value for S_IWUSR). This is caused by the driver including , it compiles fine without that header but I am unable to test drive the change. Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index 65bab3a..e7a6862 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From abc01922477104e8d72b494902aff37135c409e7 Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Thu, 12 May 2005 13:41:51 +1000 Subject: [PATCH] I2C: Setting w83627hf fan divisor 128 fails. Jarkko Lavinen provided patch to fix: "couldn't set the divisor 128 through fan1_div sysfs entry even though the chip supports it and setting divisors 1..64 worked. This was due to POWER_TO_REG() only checking 2's powers 0 till 5 but not 6." This patch applies that fix to w83627hf and w83781d drivers. Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index 4f1bff5..bd87a42 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -264,7 +264,7 @@ static inline u8 DIV_TO_REG(long val) { int i; val = SENSORS_LIMIT(val, 1, 128) >> 1; - for (i = 0; i < 6; i++) { + for (i = 0; i < 7; i++) { if (val == 0) break; val >>= 1; diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index 8912390..f47aee8 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -192,7 +192,7 @@ DIV_TO_REG(long val, enum chips type) val = SENSORS_LIMIT(val, 1, ((type == w83781d || type == as99127f) ? 8 : 128)) >> 1; - for (i = 0; i < 6; i++) { + for (i = 0; i < 7; i++) { if (val == 0) break; val >>= 1; -- cgit v0.10.2 From 937df8df907ce63b0f7e19adf6e3cdef1687fac3 Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Thu, 12 May 2005 11:59:29 +1000 Subject: [PATCH] I2C: sysfs names: rename to cpu0_vid, take 3 This small patch changes two drivers, adm1025 and adm1026, to report vid as cpu0_vid sysfs name as used by the other drivers. Added duplicated names and six month warning for old names to be removed as requested. Compile tested. Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index b9eb209..26414bc 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -83,3 +83,13 @@ Why: Deprecated in favour of the new ioctl-based rawiso interface, which is more efficient. You should really be using libraw1394 for raw1394 access anyway. Who: Jody McIntyre + +--------------------------- + +What: i2c sysfs name change: in1_ref, vid deprecated in favour of cpu0_vid +When: November 2005 +Files: drivers/i2c/chips/adm1025.c, drivers/i2c/chips/adm1026.c +Why: Match the other drivers' name for the same function, duplicate names + will be available until removal of old names. +Who: Grant Coady + diff --git a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c index 1dd823e..e452d0d 100644 --- a/drivers/i2c/chips/adm1025.c +++ b/drivers/i2c/chips/adm1025.c @@ -286,7 +286,9 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } +/* in1_ref is deprecated in favour of cpu0_vid, remove after 2005-11-11 */ static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { @@ -436,7 +438,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &dev_attr_temp1_max); device_create_file(&new_client->dev, &dev_attr_temp2_max); device_create_file(&new_client->dev, &dev_attr_alarms); + /* in1_ref is deprecated, remove after 2005-11-11 */ device_create_file(&new_client->dev, &dev_attr_in1_ref); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); device_create_file(&new_client->dev, &dev_attr_vrm); /* Pin 11 is either in4 (+12V) or VID4 */ diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c index 9d2ea21..ddbc015 100644 --- a/drivers/i2c/chips/adm1026.c +++ b/drivers/i2c/chips/adm1026.c @@ -1224,8 +1224,9 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, c struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); } - +/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1665,7 +1666,9 @@ int adm1026_detect(struct i2c_adapter *adapter, int address, device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable); device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable); device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable); + /* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ device_create_file(&new_client->dev, &dev_attr_vid); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); device_create_file(&new_client->dev, &dev_attr_vrm); device_create_file(&new_client->dev, &dev_attr_alarms); device_create_file(&new_client->dev, &dev_attr_alarm_mask); -- cgit v0.10.2 From 8e8f9289cc5b781d583d5aed935abf060207bbd3 Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Fri, 13 May 2005 20:26:10 +1000 Subject: [PATCH] I2C: adm9240 driver cleanup This patch adds an info print of detected VRM stolen from Sebastian Witt's atxp1 sriver. ADM9240 already has vrm accessor removed. Write no-op and whitespace fixes removed :) Couple of comments changed, tested on 2.6.11.9. Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/adm9240.c b/drivers/i2c/chips/adm9240.c index 0b67eab..6d609d8 100644 --- a/drivers/i2c/chips/adm9240.c +++ b/drivers/i2c/chips/adm9240.c @@ -165,7 +165,7 @@ struct adm9240_data { s8 temp_high; /* rw temp1_max */ s8 temp_hyst; /* rw temp1_max_hyst */ u16 alarms; /* ro alarms */ - u8 aout; /* rw analog_out */ + u8 aout; /* rw aout_output */ u8 vid; /* ro vid */ u8 vrm; /* -- vrm set on startup, no accessor */ }; @@ -192,7 +192,7 @@ static ssize_t show_##value(struct device *dev, char *buf) \ } show_temp(temp_high, 1000); show_temp(temp_hyst, 1000); -show_temp(temp, 500); +show_temp(temp, 500); /* 0.5'C per bit */ #define set_temp(value, reg) \ static ssize_t set_##value(struct device *dev, const char *buf, \ @@ -630,6 +630,9 @@ static void adm9240_init_client(struct i2c_client *client) data->vrm = i2c_which_vrm(); /* need this to report vid as mV */ + dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10, + data->vrm % 10); + if (conf & 1) { /* measurement cycle running: report state */ dev_info(&client->dev, "status: config 0x%02x mode %u\n", -- cgit v0.10.2 From ff3240946d6a3d9f2ecf273f7330e09eec5484eb Mon Sep 17 00:00:00 2001 From: Dominik Hackl Date: Mon, 16 May 2005 18:12:18 +0200 Subject: [PATCH] I2C: include of jiffies.h for some i2c drivers This patch includes jiffies.h in two i2c drivers. (jiffies.h is needed for the time_after function.) Signed-off-by: Dominik Hackl Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index 4a47b44..342b1a9 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "lm75.h" /* diff --git a/drivers/i2c/chips/sis5595.c b/drivers/i2c/chips/sis5595.c index c665072..6bbfc8f 100644 --- a/drivers/i2c/chips/sis5595.c +++ b/drivers/i2c/chips/sis5595.c @@ -57,6 +57,7 @@ #include #include #include +#include #include -- cgit v0.10.2 From 68188ba7de2db9999ff08a4544a78b2f10eb08bd Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 16 May 2005 18:52:38 +0200 Subject: [PATCH] I2C: Kill common macro abuse in chip drivers This patch kills a common macro abuse in i2c chip drivers: defining ALARMS_FROM_REG returning its argument unchanged. Dropping the macro makes the code somewhat more readable IMHO. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index 342b1a9..70d996d 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -169,8 +169,6 @@ static int ASB100_PWM_FROM_REG(u8 reg) return reg * 16; } -#define ALARMS_FROM_REG(val) (val) - #define DIV_FROM_REG(val) (1 << (val)) /* FAN DIV: 1, 2, 4, or 8 (defaults to 2) @@ -557,7 +555,7 @@ device_create_file(&client->dev, &dev_attr_vrm); static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 16dbfd8..7984bf9 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -172,8 +172,6 @@ static inline u8 FAN_TO_REG(long rpm, int div) ((val)+500)/1000),-128,127)) #define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) -#define ALARMS_FROM_REG(val) (val) - #define PWM_TO_REG(val) ((val) >> 1) #define PWM_FROM_REG(val) (((val)&0x7f) << 1) @@ -665,7 +663,7 @@ show_pwm_offset(3); static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct it87_data *data = it87_update_device(dev); - return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c index d618d10..b4d7fd4 100644 --- a/drivers/i2c/chips/lm85.c +++ b/drivers/i2c/chips/lm85.c @@ -284,8 +284,6 @@ static int ZONE_TO_REG( int zone ) /* i2c-vid.h defines vid_from_reg() */ #define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm))) -#define ALARMS_FROM_REG(val) (val) - /* Unlike some other drivers we DO NOT set initial limits. Use * the config file to set limits. Some users have reported * motherboards shutting down when we set limits in a previous @@ -480,7 +478,7 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index e7a6862..3140ae8 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -292,8 +292,6 @@ static inline long TEMP_FROM_REG10(u16 val) tempLUT[eightBits + 1] * twoBits) * 25; } -#define ALARMS_FROM_REG(val) (val) - #define DIV_FROM_REG(val) (1 << (val)) #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) @@ -570,7 +568,7 @@ show_fan_offset(2); /* Alarms */ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index f47aee8..4a5b06b 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -172,7 +172,6 @@ FAN_TO_REG(long rpm, int div) : (val)) / 1000, 0, 0xff)) #define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) -#define ALARMS_FROM_REG(val) (val) #define PWM_FROM_REG(val) (val) #define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) #define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ @@ -523,7 +522,7 @@ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static -- cgit v0.10.2 From be8992c249e42398ee905450688c135ab761674c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 16 May 2005 19:00:52 +0200 Subject: [PATCH] I2C: Coding style cleanups to via686a The via686a hardware monitoring driver has infamous coding style at the moment. I'd like to clean up the mess before I start working on other changes to this driver. Is the following patch acceptable? No code change, only coding style (indentation, alignments, trailing white space, a few parentheses and a typo). Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index 3140ae8..9370aaf 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -1,12 +1,12 @@ /* via686a.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - + Copyright (c) 1998 - 2002 Frodo Looijaard , Kyösti Mälkki , Mark Studebaker , and Bob Dougherty - (Some conversion-factor data were contributed by Jonathan Teh Soon Yew + (Some conversion-factor data were contributed by Jonathan Teh Soon Yew and Alex van Kaam .) This program is free software; you can redistribute it and/or modify @@ -64,19 +64,19 @@ SENSORS_INSMOD_1(via686a); /* Many VIA686A constants specified below */ /* Length of ISA address segment */ -#define VIA686A_EXTENT 0x80 -#define VIA686A_BASE_REG 0x70 -#define VIA686A_ENABLE_REG 0x74 +#define VIA686A_EXTENT 0x80 +#define VIA686A_BASE_REG 0x70 +#define VIA686A_ENABLE_REG 0x74 /* The VIA686A registers */ /* ins numbered 0-4 */ -#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) -#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) -#define VIA686A_REG_IN(nr) (0x22 + (nr)) +#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) +#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) +#define VIA686A_REG_IN(nr) (0x22 + (nr)) /* fans numbered 1-2 */ -#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) -#define VIA686A_REG_FAN(nr) (0x28 + (nr)) +#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) +#define VIA686A_REG_FAN(nr) (0x28 + (nr)) /* the following values are as speced by VIA: */ static const u8 regtemp[] = { 0x20, 0x21, 0x1f }; @@ -87,26 +87,28 @@ static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e }; #define VIA686A_REG_TEMP(nr) (regtemp[nr]) #define VIA686A_REG_TEMP_OVER(nr) (regover[nr]) #define VIA686A_REG_TEMP_HYST(nr) (reghyst[nr]) -#define VIA686A_REG_TEMP_LOW1 0x4b // bits 7-6 -#define VIA686A_REG_TEMP_LOW23 0x49 // 2 = bits 5-4, 3 = bits 7-6 - -#define VIA686A_REG_ALARM1 0x41 -#define VIA686A_REG_ALARM2 0x42 -#define VIA686A_REG_FANDIV 0x47 -#define VIA686A_REG_CONFIG 0x40 -/* The following register sets temp interrupt mode (bits 1-0 for temp1, +/* bits 7-6 */ +#define VIA686A_REG_TEMP_LOW1 0x4b +/* 2 = bits 5-4, 3 = bits 7-6 */ +#define VIA686A_REG_TEMP_LOW23 0x49 + +#define VIA686A_REG_ALARM1 0x41 +#define VIA686A_REG_ALARM2 0x42 +#define VIA686A_REG_FANDIV 0x47 +#define VIA686A_REG_CONFIG 0x40 +/* The following register sets temp interrupt mode (bits 1-0 for temp1, 3-2 for temp2, 5-4 for temp3). Modes are: 00 interrupt stays as long as value is out-of-range 01 interrupt is cleared once register is read (default) 10 comparator mode- like 00, but ignores hysteresis 11 same as 00 */ -#define VIA686A_REG_TEMP_MODE 0x4b +#define VIA686A_REG_TEMP_MODE 0x4b /* We'll just assume that you want to set all 3 simultaneously: */ -#define VIA686A_TEMP_MODE_MASK 0x3F -#define VIA686A_TEMP_MODE_CONTINUOUS (0x00) +#define VIA686A_TEMP_MODE_MASK 0x3F +#define VIA686A_TEMP_MODE_CONTINUOUS 0x00 /* Conversions. Limit checking is only done on the TO_REG - variants. + variants. ********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): @@ -119,7 +121,7 @@ static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e }; That is: volts = (25*regVal+133)*factor regVal = (volts/factor-133)/25 - (These conversions were contributed by Jonathan Teh Soon Yew + (These conversions were contributed by Jonathan Teh Soon Yew ) */ static inline u8 IN_TO_REG(long val, int inNum) { @@ -180,55 +182,55 @@ static inline u8 FAN_TO_REG(long rpm, int div) else return double(temp)*0.924-127.33; - A fifth-order polynomial fits the unofficial data (provided by Alex van - Kaam ) a bit better. It also give more reasonable - numbers on my machine (ie. they agree with what my BIOS tells me). + A fifth-order polynomial fits the unofficial data (provided by Alex van + Kaam ) a bit better. It also give more reasonable + numbers on my machine (ie. they agree with what my BIOS tells me). Here's the fifth-order fit to the 8-bit data: - temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - + temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. - (2000-10-25- RFD: thanks to Uwe Andersen for + (2000-10-25- RFD: thanks to Uwe Andersen for finding my typos in this formula!) - Alas, none of the elegant function-fit solutions will work because we - aren't allowed to use floating point in the kernel and doing it with - integers doesn't rpovide enough precision. So we'll do boring old - look-up table stuff. The unofficial data (see below) have effectively - 7-bit resolution (they are rounded to the nearest degree). I'm assuming - that the transfer function of the device is monotonic and smooth, so a - smooth function fit to the data will allow us to get better precision. + Alas, none of the elegant function-fit solutions will work because we + aren't allowed to use floating point in the kernel and doing it with + integers doesn't provide enough precision. So we'll do boring old + look-up table stuff. The unofficial data (see below) have effectively + 7-bit resolution (they are rounded to the nearest degree). I'm assuming + that the transfer function of the device is monotonic and smooth, so a + smooth function fit to the data will allow us to get better precision. I used the 5th-order poly fit described above and solved for - VIA register values 0-255. I *10 before rounding, so we get tenth-degree - precision. (I could have done all 1024 values for our 10-bit readings, - but the function is very linear in the useful range (0-80 deg C), so - we'll just use linear interpolation for 10-bit readings.) So, tempLUT + VIA register values 0-255. I *10 before rounding, so we get tenth-degree + precision. (I could have done all 1024 values for our 10-bit readings, + but the function is very linear in the useful range (0-80 deg C), so + we'll just use linear interpolation for 10-bit readings.) So, tempLUT is the temp at via register values 0-255: */ static const long tempLUT[] = - { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, - -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, - -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, - -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, - -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, - -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, - -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, - 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, - 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, - 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, - 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, - 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, - 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, - 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, - 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, - 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, - 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, - 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, - 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, - 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, - 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, - 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 +{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, + -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, + -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, + -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, + -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, + -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, + -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, + 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, + 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, + 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, + 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, + 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, + 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, + 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, + 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, + 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, + 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, + 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, + 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, + 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, + 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, + 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 }; -/* the original LUT values from Alex van Kaam +/* the original LUT values from Alex van Kaam (for via register values 12-240): {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, @@ -243,26 +245,26 @@ static const long tempLUT[] = Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed - an extra term for a good fit to these inverse data!) and then - solving for each temp value from -50 to 110 (the useable range for - this chip). Here's the fit: - viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 + an extra term for a good fit to these inverse data!) and then + solving for each temp value from -50 to 110 (the useable range for + this chip). Here's the fit: + viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) Note that n=161: */ static const u8 viaLUT[] = - { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, - 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, - 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, - 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, - 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, - 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, - 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, - 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, - 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, - 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, - 239, 240 +{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, + 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, + 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, + 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, + 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, + 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, + 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, + 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, + 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, + 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, + 239, 240 }; /* Converting temps to (8-bit) hyst and over registers @@ -270,7 +272,7 @@ static const u8 viaLUT[] = The +50 is because the temps start at -50 */ static inline u8 TEMP_TO_REG(long val) { - return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : + return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : (val < 0 ? val - 500 : val + 500) / 1000 + 50]; } @@ -289,7 +291,7 @@ static inline long TEMP_FROM_REG10(u16 val) /* do some linear interpolation */ return (tempLUT[eightBits] * (4 - twoBits) + - tempLUT[eightBits + 1] * twoBits) * 25; + tempLUT[eightBits + 1] * twoBits) * 25; } #define DIV_FROM_REG(val) (1 << (val)) @@ -354,28 +356,28 @@ static ssize_t show_in_max(struct device *dev, char *buf, int nr) { return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); } -static ssize_t set_in_min(struct device *dev, const char *buf, +static ssize_t set_in_min(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val,nr); - via686a_write_value(client, VIA686A_REG_IN_MIN(nr), + data->in_min[nr] = IN_TO_REG(val, nr); + via686a_write_value(client, VIA686A_REG_IN_MIN(nr), data->in_min[nr]); up(&data->update_lock); return count; } -static ssize_t set_in_max(struct device *dev, const char *buf, +static ssize_t set_in_max(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val,nr); - via686a_write_value(client, VIA686A_REG_IN_MAX(nr), + data->in_max[nr] = IN_TO_REG(val, nr); + via686a_write_value(client, VIA686A_REG_IN_MAX(nr), data->in_max[nr]); up(&data->update_lock); return count; @@ -431,7 +433,7 @@ static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); } -static ssize_t set_temp_over(struct device *dev, const char *buf, +static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); @@ -443,7 +445,7 @@ static ssize_t set_temp_over(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_temp_hyst(struct device *dev, const char *buf, +static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); @@ -484,7 +486,7 @@ static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\ static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ show_temp_##offset##_over, set_temp_##offset##_over); \ static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_hyst, set_temp_##offset##_hyst); + show_temp_##offset##_hyst, set_temp_##offset##_hyst); show_temp_offset(1); show_temp_offset(2); @@ -493,19 +495,19 @@ show_temp_offset(3); /* 2 Fans */ static ssize_t show_fan(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr])) ); } static ssize_t show_fan_min(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf,"%d\n", + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); } static ssize_t show_fan_div(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf,"%d\n", DIV_FROM_REG(data->fan_div[nr]) ); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); } -static ssize_t set_fan_min(struct device *dev, const char *buf, +static ssize_t set_fan_min(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); @@ -517,7 +519,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_fan_div(struct device *dev, const char *buf, +static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); @@ -608,11 +610,12 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) } /* 8231 requires multiple of 256, we enforce that on 686 as well */ - if(force_addr) + if (force_addr) address = force_addr & 0xFF00; - if(force_addr) { - dev_warn(&adapter->dev,"forcing ISA address 0x%04X\n", address); + if (force_addr) { + dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", + address); if (PCIBIOS_SUCCESSFUL != pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) return -ENODEV; @@ -621,17 +624,17 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) return -ENODEV; if (!(val & 0x0001)) { - dev_warn(&adapter->dev,"enabling sensors\n"); + dev_warn(&adapter->dev, "enabling sensors\n"); if (PCIBIOS_SUCCESSFUL != pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, - val | 0x0001)) + val | 0x0001)) return -ENODEV; } /* Reserve the ISA region */ if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) { - dev_err(&adapter->dev,"region 0x%x already in use!\n", - address); + dev_err(&adapter->dev, "region 0x%x already in use!\n", + address); return -ENODEV; } @@ -656,7 +659,7 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto ERROR3; - + /* Initialize the VIA686A chip */ via686a_init_client(new_client); @@ -695,9 +698,9 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) return 0; - ERROR3: +ERROR3: kfree(data); - ERROR0: +ERROR0: release_region(address, VIA686A_EXTENT); return err; } @@ -728,7 +731,7 @@ static void via686a_init_client(struct i2c_client *client) via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); /* Configure temp interrupt mode for continuous-interrupt operation */ - via686a_write_value(client, VIA686A_REG_TEMP_MODE, + via686a_write_value(client, VIA686A_REG_TEMP_MODE, via686a_read_value(client, VIA686A_REG_TEMP_MODE) & !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); } @@ -768,7 +771,7 @@ static struct via686a_data *via686a_update_device(struct device *dev) via686a_read_value(client, VIA686A_REG_TEMP_HYST(i)); } - /* add in lower 2 bits + /* add in lower 2 bits temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 @@ -800,35 +803,36 @@ static struct via686a_data *via686a_update_device(struct device *dev) } static struct pci_device_id via686a_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, - { 0, } + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, + { 0, } }; MODULE_DEVICE_TABLE(pci, via686a_pci_ids); static int __devinit via686a_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) + const struct pci_device_id *id) { - u16 val; - int addr = 0; - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(dev, VIA686A_BASE_REG, &val)) - return -ENODEV; - - addr = val & ~(VIA686A_EXTENT - 1); - if (addr == 0 && force_addr == 0) { - dev_err(&dev->dev,"base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - addr = force_addr; /* so detect will get called */ - - if (!addr) { - dev_err(&dev->dev,"No Via 686A sensors found.\n"); - return -ENODEV; - } - normal_isa[0] = addr; + u16 val; + int addr = 0; + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(dev, VIA686A_BASE_REG, &val)) + return -ENODEV; + + addr = val & ~(VIA686A_EXTENT - 1); + if (addr == 0 && force_addr == 0) { + dev_err(&dev->dev, "base address not set - upgrade BIOS " + "or use force_addr=0xaddr\n"); + return -ENODEV; + } + if (force_addr) + addr = force_addr; /* so detect will get called */ + + if (!addr) { + dev_err(&dev->dev, "No Via 686A sensors found.\n"); + return -ENODEV; + } + normal_isa[0] = addr; s_bridge = pci_dev_get(dev); if (i2c_add_driver(&via686a_driver)) { @@ -844,14 +848,14 @@ static int __devinit via686a_pci_probe(struct pci_dev *dev, } static struct pci_driver via686a_pci_driver = { - .name = "via686a", - .id_table = via686a_pci_ids, - .probe = via686a_pci_probe, + .name = "via686a", + .id_table = via686a_pci_ids, + .probe = via686a_pci_probe, }; static int __init sm_via686a_init(void) { - return pci_register_driver(&via686a_pci_driver); + return pci_register_driver(&via686a_pci_driver); } static void __exit sm_via686a_exit(void) @@ -865,8 +869,8 @@ static void __exit sm_via686a_exit(void) } MODULE_AUTHOR("Kyösti Mälkki , " - "Mark Studebaker " - "and Bob Dougherty "); + "Mark Studebaker " + "and Bob Dougherty "); MODULE_DESCRIPTION("VIA 686A Sensor device"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 6afe15595031bb9801af6207feed0bafc25b6e6b Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Tue, 17 May 2005 17:16:02 +1000 Subject: [PATCH] I2C: driver adm1021: remove die_code This patch removes die_code from adm1021 as nothing within the driver uses it. Signed-off-by: Grant Coady Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index f450c0b..d2c774c 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -102,8 +102,6 @@ struct adm1021_data { u8 remote_temp_hyst; u8 remote_temp_input; u8 alarms; - /* special values for ADM1021 only */ - u8 die_code; /* Special values for ADM1023 only */ u8 remote_temp_prec; u8 remote_temp_os_prec; @@ -155,7 +153,6 @@ static ssize_t show_##value(struct device *dev, struct device_attribute *attr, c return sprintf(buf, "%d\n", data->value); \ } show2(alarms); -show2(die_code); #define set(value, reg) \ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ @@ -182,7 +179,6 @@ static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remot static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static DEVICE_ATTR(die_code, S_IRUGO, show_die_code, NULL); static int adm1021_attach_adapter(struct i2c_adapter *adapter) @@ -306,8 +302,6 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &dev_attr_temp2_min); device_create_file(&new_client->dev, &dev_attr_temp2_input); device_create_file(&new_client->dev, &dev_attr_alarms); - if (data->type == adm1021) - device_create_file(&new_client->dev, &dev_attr_die_code); return 0; @@ -370,8 +364,6 @@ static struct adm1021_data *adm1021_update_device(struct device *dev) data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c; - if (data->type == adm1021) - data->die_code = adm1021_read_value(client, ADM1021_REG_DIE_CODE); if (data->type == adm1023) { data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); -- cgit v0.10.2 From 057923f0f5ba346fc128ae0a1c3842d8c12bd7f0 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 17 May 2005 18:09:36 +0200 Subject: [PATCH] I2C: chips/Kconfig corrections Here are some corrections for drivers/i2c/chips/Kconfig. Signed-off-by: Alexey Fisher Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index fa5730a..4da7641 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -29,6 +29,7 @@ config SENSORS_ADM1025 help If you say yes here you get support for Analog Devices ADM1025 and Philips NE1619 sensor chips. + This driver can also be built as a module. If so, the module will be called adm1025. @@ -38,6 +39,8 @@ config SENSORS_ADM1026 select I2C_SENSOR help If you say yes here you get support for Analog Devices ADM1026 + sensor chip. + This driver can also be built as a module. If so, the module will be called adm1026. @@ -48,6 +51,7 @@ config SENSORS_ADM1031 help If you say yes here you get support for Analog Devices ADM1031 and ADM1030 sensor chips. + This driver can also be built as a module. If so, the module will be called adm1031. @@ -198,8 +202,7 @@ config SENSORS_LM78 select I2C_SENSOR help If you say yes here you get support for National Semiconductor LM78, - LM78-J and LM79. This can also be built as a module which can be - inserted and removed while the kernel is running. + LM78-J and LM79. This driver can also be built as a module. If so, the module will be called lm78. @@ -232,7 +235,7 @@ config SENSORS_LM85 select I2C_SENSOR help If you say yes here you get support for National Semiconductor LM85 - sensor chips and clones: ADT7463 and ADM1027. + sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027. This driver can also be built as a module. If so, the module will be called lm85. -- cgit v0.10.2 From 563db2fe9e0843da9d1d85d824f022be0ada4a3c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 17 May 2005 22:38:57 +0200 Subject: [PATCH] I2C: Kill another macro abuse in via686a This patch kills another macro abuse in the via686a hardware monitoring driver. Using a macro just to alias an array is quite useless, isn't it? Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index 9370aaf..137d9b7 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -78,15 +78,10 @@ SENSORS_INSMOD_1(via686a); #define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) #define VIA686A_REG_FAN(nr) (0x28 + (nr)) -/* the following values are as speced by VIA: */ -static const u8 regtemp[] = { 0x20, 0x21, 0x1f }; -static const u8 regover[] = { 0x39, 0x3d, 0x1d }; -static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e }; - /* temps numbered 1-3 */ -#define VIA686A_REG_TEMP(nr) (regtemp[nr]) -#define VIA686A_REG_TEMP_OVER(nr) (regover[nr]) -#define VIA686A_REG_TEMP_HYST(nr) (reghyst[nr]) +static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f }; +static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d }; +static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; /* bits 7-6 */ #define VIA686A_REG_TEMP_LOW1 0x4b /* 2 = bits 5-4, 3 = bits 7-6 */ @@ -441,7 +436,8 @@ static ssize_t set_temp_over(struct device *dev, const char *buf, down(&data->update_lock); data->temp_over[nr] = TEMP_TO_REG(val); - via686a_write_value(client, VIA686A_REG_TEMP_OVER(nr), data->temp_over[nr]); + via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr], + data->temp_over[nr]); up(&data->update_lock); return count; } @@ -453,7 +449,8 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf, down(&data->update_lock); data->temp_hyst[nr] = TEMP_TO_REG(val); - via686a_write_value(client, VIA686A_REG_TEMP_HYST(nr), data->temp_hyst[nr]); + via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr], + data->temp_hyst[nr]); up(&data->update_lock); return count; } @@ -763,13 +760,13 @@ static struct via686a_data *via686a_update_device(struct device *dev) } for (i = 0; i <= 2; i++) { data->temp[i] = via686a_read_value(client, - VIA686A_REG_TEMP(i)) << 2; + VIA686A_REG_TEMP[i]) << 2; data->temp_over[i] = via686a_read_value(client, - VIA686A_REG_TEMP_OVER(i)); + VIA686A_REG_TEMP_OVER[i]); data->temp_hyst[i] = via686a_read_value(client, - VIA686A_REG_TEMP_HYST(i)); + VIA686A_REG_TEMP_HYST[i]); } /* add in lower 2 bits temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 -- cgit v0.10.2 From 6f637a6494a1872c613fe68f64ea4831c3e5b037 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 21 Jun 2005 21:01:59 -0700 Subject: [PATCH] I2C: fix up some sysfs device attribute file parameters Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/adm9240.c b/drivers/i2c/chips/adm9240.c index 6d609d8..5c68e9c 100644 --- a/drivers/i2c/chips/adm9240.c +++ b/drivers/i2c/chips/adm9240.c @@ -185,7 +185,9 @@ static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) /* temperature */ #define show_temp(value, scale) \ -static ssize_t show_##value(struct device *dev, char *buf) \ +static ssize_t show_##value(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ struct adm9240_data *data = adm9240_update_device(dev); \ return sprintf(buf, "%d\n", data->value * scale); \ @@ -195,8 +197,9 @@ show_temp(temp_hyst, 1000); show_temp(temp, 500); /* 0.5'C per bit */ #define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, const char *buf, \ - size_t count) \ +static ssize_t set_##value(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct adm9240_data *data = adm9240_update_device(dev); \ @@ -266,26 +269,36 @@ static ssize_t set_in_max(struct device *dev, const char *buf, } #define show_in_offset(offset) \ -static ssize_t show_in##offset(struct device *dev, char *buf) \ +static ssize_t show_in##offset(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ return show_in(dev, buf, offset); \ } \ static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ -static ssize_t show_in##offset##_min(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_min(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ return show_in_min(dev, buf, offset); \ } \ -static ssize_t show_in##offset##_max(struct device *dev, char *buf) \ +static ssize_t show_in##offset##_max(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ return show_in_max(dev, buf, offset); \ } \ static ssize_t \ -set_in##offset##_min(struct device *dev, const char *buf, size_t count) \ +set_in##offset##_min(struct device *dev, \ + struct device_attribute *attr, const char *buf, \ + size_t count) \ { \ return set_in_min(dev, buf, count, offset); \ } \ static ssize_t \ -set_in##offset##_max(struct device *dev, const char *buf, size_t count) \ +set_in##offset##_max(struct device *dev, \ + struct device_attribute *attr, const char *buf, \ + size_t count) \ { \ return set_in_max(dev, buf, count, offset); \ } \ @@ -401,20 +414,27 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, } #define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ return show_fan(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_div (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ return show_fan_div(dev, buf, offset - 1); \ } \ -static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +static ssize_t show_fan_##offset##_min (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ return show_fan_min(dev, buf, offset - 1); \ } \ static ssize_t set_fan_##offset##_min (struct device *dev, \ -const char *buf, size_t count) \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ return set_fan_min(dev, buf, count, offset - 1); \ } \ @@ -429,7 +449,7 @@ show_fan_offset(1); show_fan_offset(2); /* alarms */ -static ssize_t show_alarms(struct device *dev, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%u\n", data->alarms); @@ -437,7 +457,7 @@ static ssize_t show_alarms(struct device *dev, char *buf) static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* vid */ -static ssize_t show_vid(struct device *dev, char *buf) +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); @@ -445,13 +465,13 @@ static ssize_t show_vid(struct device *dev, char *buf) static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); /* analog output */ -static ssize_t show_aout(struct device *dev, char *buf) +static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); } -static ssize_t set_aout(struct device *dev, const char *buf, size_t count) +static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); @@ -466,7 +486,7 @@ static ssize_t set_aout(struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); /* chassis_clear */ -static ssize_t chassis_clear(struct device *dev, const char *buf, size_t count) +static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); unsigned long val = simple_strtol(buf, NULL, 10); diff --git a/drivers/i2c/chips/atxp1.c b/drivers/i2c/chips/atxp1.c index 57b0bdd..5c6597a 100644 --- a/drivers/i2c/chips/atxp1.c +++ b/drivers/i2c/chips/atxp1.c @@ -99,7 +99,7 @@ static struct atxp1_data * atxp1_update_device(struct device *dev) } /* sys file functions for cpu0_vid */ -static ssize_t atxp1_showvcore(struct device *dev, char *buf) +static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf) { int size; struct atxp1_data *data; @@ -111,7 +111,7 @@ static ssize_t atxp1_showvcore(struct device *dev, char *buf) return size; } -static ssize_t atxp1_storevcore(struct device *dev, const char* buf, size_t count) +static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct atxp1_data *data; struct i2c_client *client; @@ -169,7 +169,7 @@ static ssize_t atxp1_storevcore(struct device *dev, const char* buf, size_t coun static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore); /* sys file functions for GPIO1 */ -static ssize_t atxp1_showgpio1(struct device *dev, char *buf) +static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf) { int size; struct atxp1_data *data; @@ -181,7 +181,7 @@ static ssize_t atxp1_showgpio1(struct device *dev, char *buf) return size; } -static ssize_t atxp1_storegpio1(struct device *dev, const char* buf, size_t count) +static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count) { struct atxp1_data *data; struct i2c_client *client; @@ -211,7 +211,7 @@ static ssize_t atxp1_storegpio1(struct device *dev, const char* buf, size_t coun static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); /* sys file functions for GPIO2 */ -static ssize_t atxp1_showgpio2(struct device *dev, char *buf) +static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf) { int size; struct atxp1_data *data; @@ -223,7 +223,7 @@ static ssize_t atxp1_showgpio2(struct device *dev, char *buf) return size; } -static ssize_t atxp1_storegpio2(struct device *dev, const char* buf, size_t count) +static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct atxp1_data *data; struct i2c_client *client; diff --git a/drivers/i2c/chips/w83627ehf.c b/drivers/i2c/chips/w83627ehf.c index 4fcc823..8a40b69 100644 --- a/drivers/i2c/chips/w83627ehf.c +++ b/drivers/i2c/chips/w83627ehf.c @@ -486,7 +486,8 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr) #define sysfs_fan_offset(offset) \ static ssize_t \ -show_reg_fan_##offset(struct device *dev, char *buf) \ +show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ return show_fan(dev, buf, offset-1); \ } \ @@ -495,13 +496,14 @@ static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ #define sysfs_fan_min_offset(offset) \ static ssize_t \ -show_reg_fan##offset##_min(struct device *dev, char *buf) \ +show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ return show_fan_min(dev, buf, offset-1); \ } \ static ssize_t \ -store_reg_fan##offset##_min(struct device *dev, const char *buf, \ - size_t count) \ +store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ return store_fan_min(dev, buf, count, offset-1); \ } \ @@ -511,7 +513,8 @@ static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ #define sysfs_fan_div_offset(offset) \ static ssize_t \ -show_reg_fan##offset##_div(struct device *dev, char *buf) \ +show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ return show_fan_div(dev, buf, offset - 1); \ } \ @@ -536,7 +539,8 @@ sysfs_fan_div_offset(5); #define show_temp1_reg(reg) \ static ssize_t \ -show_##reg(struct device *dev, char *buf) \ +show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct w83627ehf_data *data = w83627ehf_update_device(dev); \ return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \ @@ -547,7 +551,8 @@ show_temp1_reg(temp1_max_hyst); #define store_temp1_reg(REG, reg) \ static ssize_t \ -store_temp1_##reg(struct device *dev, const char *buf, size_t count) \ +store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct w83627ehf_data *data = i2c_get_clientdata(client); \ @@ -601,7 +606,8 @@ store_temp_reg(HYST, temp_max_hyst); #define sysfs_temp_offset(offset) \ static ssize_t \ -show_reg_temp##offset (struct device *dev, char *buf) \ +show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ return show_temp(dev, buf, offset - 2); \ } \ @@ -610,13 +616,14 @@ static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ #define sysfs_temp_reg_offset(reg, offset) \ static ssize_t \ -show_reg_temp##offset##_##reg(struct device *dev, char *buf) \ +show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ return show_temp_##reg(dev, buf, offset - 2); \ } \ static ssize_t \ -store_reg_temp##offset##_##reg(struct device *dev, const char *buf, \ - size_t count) \ +store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ return store_temp_##reg(dev, buf, count, offset - 2); \ } \ -- cgit v0.10.2 From 46b615f453202dbcf66452b500ab69c0e2148593 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 19 May 2005 22:27:23 +0200 Subject: [PATCH] I2C: Spelling fixes for drivers/i2c/algos/i2c-algo-pca.c This patch fixes the some misspellings and a trailing whitespace in the comments. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index dfa77eb..cc3a952 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -62,7 +62,7 @@ static void pca_start(struct i2c_algo_pca_data *adap) } /* - * Generate a repeated start condition on the i2c bus + * Generate a repeated start condition on the i2c bus * * return after the repeated start condition has occurred */ @@ -82,7 +82,7 @@ static void pca_repeated_start(struct i2c_algo_pca_data *adap) * returns after the stop condition has been generated * * STOPs do not generate an interrupt or set the SI flag, since the - * part returns the the idle state (0xf8). Hence we don't need to + * part returns the idle state (0xf8). Hence we don't need to * pca_wait here. */ static void pca_stop(struct i2c_algo_pca_data *adap) -- cgit v0.10.2 From 614e24be139c0ae70378349e6c6f0e21751e56bf Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 19 May 2005 21:39:06 +0200 Subject: [PATCH] I2C: Spelling fixes for drivers/i2c/busses/i2c-parport.c This patch fixes a double "the" in a comment section. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 112d491..71a2502 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -130,7 +130,7 @@ static int parport_getsda(void *data) /* Encapsulate the functions above in the correct structure. Note that this is only a template, from which the real structures are copied. The attaching code will set getscl to NULL for adapters that - cannot read SCL back, and will also make the the data field point to + cannot read SCL back, and will also make the data field point to the parallel port structure. */ static struct i2c_algo_bit_data parport_algo_data = { .setsda = parport_setsda, -- cgit v0.10.2 From a551acc2cb1f13a9bd728b8cf86f9adafefdcfb2 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 19 May 2005 21:40:38 +0200 Subject: [PATCH] I2C: Spelling fixes for drivers/i2c/i2c-core.c This patch fixes a misspelling in a comment section. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f503428..51ce268 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -238,7 +238,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) } /* detach any active clients. This must be done first, because - * it can fail; in which case we give upp. */ + * it can fail; in which case we give up. */ list_for_each_safe(item, _n, &adap->clients) { client = list_entry(item, struct i2c_client, list); -- cgit v0.10.2 From d68a861d857c11a017a8f755fa250afaf8b1bcdb Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 19 May 2005 21:41:47 +0200 Subject: [PATCH] I2C: Spelling fixes for drivers/i2c/i2c-dev.c This patch fixes a misspelling in a comment section. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index cb217c4..bc5d557 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -213,7 +213,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, sizeof(rdwr_arg))) return -EFAULT; - /* Put an arbritrary limit on the number of messages that can + /* Put an arbitrary limit on the number of messages that can * be sent at once */ if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) return -EINVAL; -- cgit v0.10.2 From 7f02d56e54f2a8afaa01974df650ace9dc15d0cd Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 18 May 2005 19:39:57 +0200 Subject: [PATCH] i2c: Race fix for i2c-mpc.c i2c: Race fix for i2c-mpc.c The problem was that the clock speed and driver data is initialized after the i2c adapter was added. This caused the i2c bus to start working at a wrong speed. (Mostly noticable on the second bus on mpc5200) With this patch we've tried to keep the i2c adapter working perfectly all the time it is included in the system. Initialize before added, Remove garbage after deleleted. Submitted-by: Asier Llano Palacios Signed-off-by: Sylvain Munaut Signed-off-by: Kumar Gala Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index c8a8703..d41ca31 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -333,6 +333,9 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) } else i2c->irq = 0; + mpc_i2c_setclock(i2c); + ocp_set_drvdata(ocp, i2c); + i2c->adap = mpc_ops; i2c_set_adapdata(&i2c->adap, i2c); @@ -341,8 +344,6 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) goto fail_add; } - mpc_i2c_setclock(i2c); - ocp_set_drvdata(ocp, i2c); return result; fail_add: @@ -358,8 +359,8 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) static void __devexit mpc_i2c_remove(struct ocp_device *ocp) { struct mpc_i2c *i2c = ocp_get_drvdata(ocp); - ocp_set_drvdata(ocp, NULL); i2c_del_adapter(&i2c->adap); + ocp_set_drvdata(ocp, NULL); if (ocp->def->irq != OCP_IRQ_NA) free_irq(i2c->irq, i2c); @@ -430,6 +431,9 @@ static int fsl_i2c_probe(struct device *device) goto fail_irq; } + mpc_i2c_setclock(i2c); + dev_set_drvdata(device, i2c); + i2c->adap = mpc_ops; i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.dev.parent = &pdev->dev; @@ -438,8 +442,6 @@ static int fsl_i2c_probe(struct device *device) goto fail_add; } - mpc_i2c_setclock(i2c); - dev_set_drvdata(device, i2c); return result; fail_add: @@ -456,8 +458,8 @@ static int fsl_i2c_remove(struct device *device) { struct mpc_i2c *i2c = dev_get_drvdata(device); - dev_set_drvdata(device, NULL); i2c_del_adapter(&i2c->adap); + dev_set_drvdata(device, NULL); if (i2c->irq != 0) free_irq(i2c->irq, i2c); -- cgit v0.10.2 From cc0b07ed479fd92806aef7d6dbc58b6dc6da3796 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 22 May 2005 09:39:11 +0200 Subject: [PATCH] I2C: Sensors mailing list has moved The following patch updates all references to the sensors mailing list, so as to reflect the fact that the list recently moved to a new home and changed addresses. I'll work out a similar patch for Linux 2.4 soon. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/i2c/busses/i2c-sis69x b/Documentation/i2c/busses/i2c-sis69x index 5be4876..b88953d 100644 --- a/Documentation/i2c/busses/i2c-sis69x +++ b/Documentation/i2c/busses/i2c-sis69x @@ -42,7 +42,7 @@ I suspect that this driver could be made to work for the following SiS chipsets as well: 635, and 635T. If anyone owns a board with those chips AND is willing to risk crashing & burning an otherwise well-behaved kernel in the name of progress... please contact me at or -via the project's mailing list: . Please +via the project's mailing list: . Please send bug reports and/or success stories as well. diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index 5640491..a7adbdd 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients @@ -57,7 +57,7 @@ Technical changes: Documentation/i2c/sysfs-interface for the individual files. Also convert the units these files read and write to the specified ones. If you need to add a new type of file, please discuss it on the - sensors mailing list by providing a + sensors mailing list by providing a patch to the Documentation/i2c/sysfs-interface file. * [Attach] For I2C drivers, the attach function should make sure diff --git a/MAINTAINERS b/MAINTAINERS index 0f88a70..4d44824 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -194,7 +194,7 @@ S: Maintained ADM1025 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Maintained ADT746X FAN DRIVER @@ -242,7 +242,7 @@ S: Maintained ALI1563 I2C DRIVER P: Rudolf Marek M: r.marek@sh.cvut.cz -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Maintained ALPHA PORT @@ -1002,7 +1002,7 @@ P: Greg Kroah-Hartman M: greg@kroah.com P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org W: http://www.lm-sensors.nu/ S: Maintained @@ -1430,13 +1430,13 @@ S: Supported LM83 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Maintained LM90 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Maintained LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks) @@ -2075,7 +2075,7 @@ S: Maintained SMSC47M1 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Odd Fixes SMB FILESYSTEM @@ -2614,7 +2614,7 @@ S: Orphan W1 DALLAS'S 1-WIRE BUS P: Evgeniy Polyakov M: johnpol@2ka.mipt.ru -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Maintained W83L51xD SD/MMC CARD INTERFACE DRIVER @@ -2627,7 +2627,7 @@ S: Maintained W83L785TS HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Odd Fixes WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) -- cgit v0.10.2 From 72cd799544f2b36c2f07ceaeed6d984cb130d4f3 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 24 May 2005 17:34:51 -0700 Subject: [PATCH] I2C: add i2c driver for TPS6501x This adds an I2C driver for the TPS6501x series of power management chips. It's used on many OMAP based boards, and this driver has been widely used in the Linux-OMAP trees over the last year or so. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 4da7641..028a6fe 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -1,5 +1,5 @@ # -# I2C Sensor device configuration +# I2C Sensor and "other" chip configuration # menu "Hardware Sensors Chip support" @@ -472,6 +472,23 @@ config ISP1301_OMAP This driver can also be built as a module. If so, the module will be called isp1301_omap. +# NOTE: This isn't really OMAP-specific, except for the current +# interface location in +# and having mostly OMAP-specific board support +config TPS65010 + tristate "TPS6501x Power Management chips" + depends on I2C && ARCH_OMAP + default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK + help + If you say yes here you get support for the TPS6501x series of + Power Management chips. These include voltage regulators, + lithium ion/polymer battery charging, and other features that + are often used in portable devices like cell phones and cameras. + + This driver can also be built as a module. If so, the module + will be called tps65010. + + config SENSORS_M41T00 tristate "ST M41T00 RTC chip" depends on I2C && PPC32 diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 2281435..5054ba5 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -1,5 +1,5 @@ # -# Makefile for the kernel hardware sensors chip drivers. +# Makefile for sensor and "other" I2C chip drivers. # # asb100, then w83781d go first, as they can override other drivers' addresses. @@ -43,7 +43,9 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o + obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o +obj-$(CONFIG_TPS65010) += tps65010.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c new file mode 100644 index 0000000..c0ac01b --- /dev/null +++ b/drivers/i2c/chips/tps65010.c @@ -0,0 +1,1072 @@ +/* + * tps65010 - driver for tps6501x power management chips + * + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2004-2005 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/*-------------------------------------------------------------------------*/ + +#define DRIVER_VERSION "2 May 2005" +#define DRIVER_NAME (tps65010_driver.name) + +MODULE_DESCRIPTION("TPS6501x Power Management Driver"); +MODULE_LICENSE("GPL"); + +/* only two addresses possible */ +#define TPS_BASE 0x48 +static unsigned short normal_i2c[] = { + TPS_BASE, + I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD; + +static struct i2c_driver tps65010_driver; + +/*-------------------------------------------------------------------------*/ + +/* This driver handles a family of multipurpose chips, which incorporate + * voltage regulators, lithium ion/polymer battery charging, GPIOs, LEDs, + * and other features often needed in portable devices like cell phones + * or digital cameras. + * + * The tps65011 and tps65013 have different voltage settings compared + * to tps65010 and tps65012. The tps65013 has a NO_CHG status/irq. + * All except tps65010 have "wait" mode, possibly defaulted so that + * battery-insert != device-on. + * + * We could distinguish between some models by checking VDCDC1.UVLO or + * other registers, unless they've been changed already after powerup + * as part of board setup by a bootloader. + */ +enum tps_model { + TPS_UNKNOWN = 0, + TPS65010, + TPS65011, + TPS65012, + TPS65013, +}; + +struct tps65010 { + struct i2c_client client; + struct semaphore lock; + int irq; + struct work_struct work; + struct dentry *file; + unsigned charging:1; + unsigned por:1; + unsigned model:8; + u16 vbus; + unsigned long flags; +#define FLAG_VBUS_CHANGED 0 +#define FLAG_IRQ_ENABLE 1 + + /* copies of last register state */ + u8 chgstatus, regstatus, chgconf; + u8 nmask1, nmask2; + + /* plus four GPIOs, probably used to switch power */ +}; + +#define POWER_POLL_DELAY msecs_to_jiffies(800) + +/*-------------------------------------------------------------------------*/ + +#if defined(DEBUG) || defined(CONFIG_DEBUG_FS) + +static void dbg_chgstat(char *buf, size_t len, u8 chgstatus) +{ + snprintf(buf, len, "%02x%s%s%s%s%s%s%s%s\n", + chgstatus, + (chgstatus & TPS_CHG_USB) ? " USB" : "", + (chgstatus & TPS_CHG_AC) ? " AC" : "", + (chgstatus & TPS_CHG_THERM) ? " therm" : "", + (chgstatus & TPS_CHG_TERM) ? " done" : + ((chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) + ? " (charging)" : ""), + (chgstatus & TPS_CHG_TAPER_TMO) ? " taper_tmo" : "", + (chgstatus & TPS_CHG_CHG_TMO) ? " charge_tmo" : "", + (chgstatus & TPS_CHG_PRECHG_TMO) ? " prechg_tmo" : "", + (chgstatus & TPS_CHG_TEMP_ERR) ? " temp_err" : ""); +} + +static void dbg_regstat(char *buf, size_t len, u8 regstatus) +{ + snprintf(buf, len, "%02x %s%s%s%s%s%s%s%s\n", + regstatus, + (regstatus & TPS_REG_ONOFF) ? "off" : "(on)", + (regstatus & TPS_REG_COVER) ? " uncover" : "", + (regstatus & TPS_REG_UVLO) ? " UVLO" : "", + (regstatus & TPS_REG_NO_CHG) ? " NO_CHG" : "", + (regstatus & TPS_REG_PG_LD02) ? " ld01_bad" : "", + (regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "", + (regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "", + (regstatus & TPS_REG_PG_CORE) ? " core_bad" : ""); +} + +static void dbg_chgconf(int por, char *buf, size_t len, u8 chgconfig) +{ + char *hibit; + + if (por) + hibit = (chgconfig & TPS_CHARGE_POR) + ? "POR=69ms" : "POR=1sec"; + else + hibit = (chgconfig & TPS65013_AUA) ? "AUA" : ""; + + snprintf(buf, len, "%02x %s%s%s AC=%d%% USB=%dmA %sCharge\n", + chgconfig, hibit, + (chgconfig & TPS_CHARGE_RESET) ? " reset" : "", + (chgconfig & TPS_CHARGE_FAST) ? " fast" : "", + ({int p; switch ((chgconfig >> 3) & 3) { + case 3: p = 100; break; + case 2: p = 75; break; + case 1: p = 50; break; + default: p = 25; break; + }; p; }), + (chgconfig & TPS_VBUS_CHARGING) + ? ((chgconfig & TPS_VBUS_500MA) ? 500 : 100) + : 0, + (chgconfig & TPS_CHARGE_ENABLE) ? "" : "No"); +} + +#endif + +#ifdef DEBUG + +static void show_chgstatus(const char *label, u8 chgstatus) +{ + char buf [100]; + + dbg_chgstat(buf, sizeof buf, chgstatus); + pr_debug("%s: %s %s", DRIVER_NAME, label, buf); +} + +static void show_regstatus(const char *label, u8 regstatus) +{ + char buf [100]; + + dbg_regstat(buf, sizeof buf, regstatus); + pr_debug("%s: %s %s", DRIVER_NAME, label, buf); +} + +static void show_chgconfig(int por, const char *label, u8 chgconfig) +{ + char buf [100]; + + dbg_chgconf(por, buf, sizeof buf, chgconfig); + pr_debug("%s: %s %s", DRIVER_NAME, label, buf); +} + +#else + +static inline void show_chgstatus(const char *label, u8 chgstatus) { } +static inline void show_regstatus(const char *label, u8 chgstatus) { } +static inline void show_chgconfig(int por, const char *label, u8 chgconfig) { } + +#endif + +#ifdef CONFIG_DEBUG_FS + +static int dbg_show(struct seq_file *s, void *_) +{ + struct tps65010 *tps = s->private; + u8 value, v2; + unsigned i; + char buf[100]; + const char *chip; + + switch (tps->model) { + case TPS65010: chip = "tps65010"; break; + case TPS65011: chip = "tps65011"; break; + case TPS65012: chip = "tps65012"; break; + case TPS65013: chip = "tps65013"; break; + default: chip = NULL; break; + } + seq_printf(s, "driver %s\nversion %s\nchip %s\n\n", + DRIVER_NAME, DRIVER_VERSION, chip); + + down(&tps->lock); + + /* FIXME how can we tell whether a battery is present? + * likely involves a charge gauging chip (like BQ26501). + */ + + seq_printf(s, "%scharging\n\n", tps->charging ? "" : "(not) "); + + + /* registers for monitoring battery charging and status; note + * that reading chgstat and regstat may ack IRQs... + */ + value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + dbg_chgconf(tps->por, buf, sizeof buf, value); + seq_printf(s, "chgconfig %s", buf); + + value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); + dbg_chgstat(buf, sizeof buf, value); + seq_printf(s, "chgstat %s", buf); + value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK1); + dbg_chgstat(buf, sizeof buf, value); + seq_printf(s, "mask1 %s", buf); + /* ignore ackint1 */ + + value = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); + dbg_regstat(buf, sizeof buf, value); + seq_printf(s, "regstat %s", buf); + value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK2); + dbg_regstat(buf, sizeof buf, value); + seq_printf(s, "mask2 %s\n", buf); + /* ignore ackint2 */ + + (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); + + + /* VMAIN voltage, enable lowpower, etc */ + value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1); + seq_printf(s, "vdcdc1 %02x\n", value); + + /* VCORE voltage, vibrator on/off */ + value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2); + seq_printf(s, "vdcdc2 %02x\n", value); + + /* both LD0s, and their lowpower behavior */ + value = i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1); + seq_printf(s, "vregs1 %02x\n\n", value); + + + /* LEDs and GPIOs */ + value = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_ON); + v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_PER); + seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n", + (value & 0x80) + ? ((v2 & 0x80) ? "on" : "off") + : ((v2 & 0x80) ? "blink" : "(nPG)"), + value, v2, + (value & 0x7f) * 10, (v2 & 0x7f) * 100); + + value = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_ON); + v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_PER); + seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n", + (value & 0x80) + ? ((v2 & 0x80) ? "on" : "off") + : ((v2 & 0x80) ? "blink" : "off"), + value, v2, + (value & 0x7f) * 10, (v2 & 0x7f) * 100); + + value = i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO); + v2 = i2c_smbus_read_byte_data(&tps->client, TPS_MASK3); + seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2); + + for (i = 0; i < 4; i++) { + if (value & (1 << (4 +i))) + seq_printf(s, " gpio%d-out %s\n", i + 1, + (value & (1 << i)) ? "low" : "hi "); + else + seq_printf(s, " gpio%d-in %s %s %s\n", i + 1, + (value & (1 << i)) ? "hi " : "low", + (v2 & (1 << i)) ? "no-irq" : "irq", + (v2 & (1 << (4 + i))) ? "rising" : "falling"); + } + + up(&tps->lock); + return 0; +} + +static int dbg_tps_open(struct inode *inode, struct file *file) +{ + return single_open(file, dbg_show, inode->u.generic_ip); +} + +static struct file_operations debug_fops = { + .open = dbg_tps_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define DEBUG_FOPS &debug_fops + +#else +#define DEBUG_FOPS NULL +#endif + +/*-------------------------------------------------------------------------*/ + +/* handle IRQS in a task context, so we can use I2C calls */ +static void tps65010_interrupt(struct tps65010 *tps) +{ + u8 tmp = 0, mask, poll; + + /* IRQs won't trigger irqs for certain events, but we can get + * others by polling (normally, with external power applied). + */ + poll = 0; + + /* regstatus irqs */ + if (tps->nmask2) { + tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); + mask = tmp ^ tps->regstatus; + tps->regstatus = tmp; + mask &= tps->nmask2; + } else + mask = 0; + if (mask) { + tps->regstatus = tmp; + /* may need to shut something down ... */ + + /* "off" usually means deep sleep */ + if (tmp & TPS_REG_ONOFF) { + pr_info("%s: power off button\n", DRIVER_NAME); +#if 0 + /* REVISIT: this might need its own workqueue + * plus tweaks including deadlock avoidance ... + */ + software_suspend(); +#endif + poll = 1; + } + } + + /* chgstatus irqs */ + if (tps->nmask1) { + tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); + mask = tmp ^ tps->chgstatus; + tps->chgstatus = tmp; + mask &= tps->nmask1; + } else + mask = 0; + if (mask) { + unsigned charging = 0; + + show_chgstatus("chg/irq", tmp); + if (tmp & (TPS_CHG_USB|TPS_CHG_AC)) + show_chgconfig(tps->por, "conf", tps->chgconf); + + /* Unless it was turned off or disabled, we charge any + * battery whenever there's power available for it + * and the charger hasn't been disabled. + */ + if (!(tps->chgstatus & ~(TPS_CHG_USB|TPS_CHG_AC)) + && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) + && (tps->chgconf & TPS_CHARGE_ENABLE) + ) { + if (tps->chgstatus & TPS_CHG_USB) { + /* VBUS options are readonly until reconnect */ + if (mask & TPS_CHG_USB) + set_bit(FLAG_VBUS_CHANGED, &tps->flags); + charging = 1; + } else if (tps->chgstatus & TPS_CHG_AC) + charging = 1; + } + if (charging != tps->charging) { + tps->charging = charging; + pr_info("%s: battery %scharging\n", + DRIVER_NAME, charging ? "" : + ((tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) + ? "NOT " : "dis")); + } + } + + /* always poll to detect (a) power removal, without tps65013 + * NO_CHG IRQ; or (b) restart of charging after stop. + */ + if ((tps->model != TPS65013 || !tps->charging) + && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))) + poll = 1; + if (poll) + (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); + + /* also potentially gpio-in rise or fall */ +} + +/* handle IRQs and polling using keventd for now */ +static void tps65010_work(void *_tps) +{ + struct tps65010 *tps = _tps; + + down(&tps->lock); + + tps65010_interrupt(tps); + + if (test_and_clear_bit(FLAG_VBUS_CHANGED, &tps->flags)) { + int status; + u8 chgconfig, tmp; + + chgconfig = i2c_smbus_read_byte_data(&tps->client, + TPS_CHGCONFIG); + chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING); + if (tps->vbus == 500) + chgconfig |= TPS_VBUS_500MA | TPS_VBUS_CHARGING; + else if (tps->vbus >= 100) + chgconfig |= TPS_VBUS_CHARGING; + + status = i2c_smbus_write_byte_data(&tps->client, + TPS_CHGCONFIG, chgconfig); + + /* vbus update fails unless VBUS is connected! */ + tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + tps->chgconf = tmp; + show_chgconfig(tps->por, "update vbus", tmp); + } + + if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags)) + enable_irq(tps->irq); + + up(&tps->lock); +} + +static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs) +{ + struct tps65010 *tps = _tps; + + disable_irq_nosync(irq); + set_bit(FLAG_IRQ_ENABLE, &tps->flags); + (void) schedule_work(&tps->work); + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +static struct tps65010 *the_tps; + +static int __exit tps65010_detach_client(struct i2c_client *client) +{ + struct tps65010 *tps; + + tps = container_of(client, struct tps65010, client); +#ifdef CONFIG_ARM + if (machine_is_omap_h2()) + omap_free_gpio(58); + if (machine_is_omap_osk()) + omap_free_gpio(OMAP_MPUIO(1)); +#endif + free_irq(tps->irq, tps); + debugfs_remove(tps->file); + if (i2c_detach_client(client) == 0) + kfree(tps); + the_tps = 0; + return 0; +} + +static int tps65010_noscan(struct i2c_adapter *bus) +{ + /* pure paranoia, in case someone adds another i2c bus + * after our init section's gone... + */ + return -ENODEV; +} + +/* no error returns, they'd just make bus scanning stop */ +static int __init +tps65010_probe(struct i2c_adapter *bus, int address, int kind) +{ + struct tps65010 *tps; + int status; + + if (the_tps) { + dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME); + return 0; + } + + tps = kmalloc(sizeof *tps, GFP_KERNEL); + if (!tps) + return 0; + + memset(tps, 0, sizeof *tps); + init_MUTEX(&tps->lock); + INIT_WORK(&tps->work, tps65010_work, tps); + tps->irq = -1; + tps->client.addr = address; + i2c_set_clientdata(&tps->client, tps); + tps->client.adapter = bus; + tps->client.driver = &tps65010_driver; + strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE); + + status = i2c_attach_client(&tps->client); + if (status < 0) { + dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", + DRIVER_NAME, address, status); +fail1: + kfree(tps); + return 0; + } + +#ifdef CONFIG_ARM + if (machine_is_omap_h2()) { + tps->model = TPS65010; + omap_cfg_reg(W4_GPIO58); + tps->irq = OMAP_GPIO_IRQ(58); + omap_request_gpio(58); + omap_set_gpio_direction(58, 1); + omap_set_gpio_edge_ctrl(58, OMAP_GPIO_FALLING_EDGE); + } + if (machine_is_omap_osk()) { + tps->model = TPS65010; + // omap_cfg_reg(U19_1610_MPUIO1); + tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); + omap_request_gpio(OMAP_MPUIO(1)); + omap_set_gpio_direction(OMAP_MPUIO(1), 1); + omap_set_gpio_edge_ctrl(OMAP_MPUIO(1), OMAP_GPIO_FALLING_EDGE); + } + if (machine_is_omap_h3()) { + tps->model = TPS65013; + + // FIXME set up this board's IRQ ... + } +#else +#define set_irq_type(num,trigger) do{}while(0) +#endif + + if (tps->irq > 0) { + set_irq_type(tps->irq, IRQT_LOW); + status = request_irq(tps->irq, tps65010_irq, + SA_SAMPLE_RANDOM, DRIVER_NAME, tps); + if (status < 0) { + dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n", + tps->irq, status); + i2c_detach_client(&tps->client); + goto fail1; + } +#ifdef CONFIG_ARM + /* annoying race here, ideally we'd have an option + * to claim the irq now and enable it later. + */ + disable_irq(tps->irq); + set_bit(FLAG_IRQ_ENABLE, &tps->flags); +#endif + } else + printk(KERN_WARNING "%s: IRQ not configured!\n", + DRIVER_NAME); + + + switch (tps->model) { + case TPS65010: + case TPS65012: + tps->por = 1; + break; + case TPS_UNKNOWN: + printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME); + break; + /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */ + } + tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + show_chgconfig(tps->por, "conf/init", tps->chgconf); + + show_chgstatus("chg/init", + i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS)); + show_regstatus("reg/init", + i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS)); + + pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1), + i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2), + i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1)); + pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO), + i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); + + tps65010_driver.attach_adapter = tps65010_noscan; + the_tps = tps; + +#if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG) + /* USB hosts can't draw VBUS. OTG devices could, later + * when OTG infrastructure enables it. USB peripherals + * could be relying on VBUS while booting, though. + */ + tps->vbus = 100; +#endif + + /* unmask the "interesting" irqs, then poll once to + * kickstart monitoring, initialize shadowed status + * registers, and maybe disable VBUS draw. + */ + tps->nmask1 = ~0; + (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1); + + tps->nmask2 = TPS_REG_ONOFF; + if (tps->model == TPS65013) + tps->nmask2 |= TPS_REG_NO_CHG; + (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2); + + (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f + | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); + + tps65010_work(tps); + + tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL, + tps, DEBUG_FOPS); + return 0; +} + +static int __init tps65010_scan_bus(struct i2c_adapter *bus) +{ + if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EINVAL; + return i2c_probe(bus, &addr_data, tps65010_probe); +} + +static struct i2c_driver tps65010_driver = { + .owner = THIS_MODULE, + .name = "tps65010", + .id = 888, /* FIXME assign "official" value */ + .flags = I2C_DF_NOTIFY, + .attach_adapter = tps65010_scan_bus, + .detach_client = __exit_p(tps65010_detach_client), +}; + +/*-------------------------------------------------------------------------*/ + +/* Draw from VBUS: + * 0 mA -- DON'T DRAW (might supply power instead) + * 100 mA -- usb unit load (slowest charge rate) + * 500 mA -- usb high power (fast battery charge) + */ +int tps65010_set_vbus_draw(unsigned mA) +{ + unsigned long flags; + + if (!the_tps) + return -ENODEV; + + /* assumes non-SMP */ + local_irq_save(flags); + if (mA >= 500) + mA = 500; + else if (mA >= 100) + mA = 100; + else + mA = 0; + the_tps->vbus = mA; + if ((the_tps->chgstatus & TPS_CHG_USB) + && test_and_set_bit( + FLAG_VBUS_CHANGED, &the_tps->flags)) { + /* gadget drivers call this in_irq() */ + (void) schedule_work(&the_tps->work); + } + local_irq_restore(flags); + + return 0; +} +EXPORT_SYMBOL(tps65010_set_vbus_draw); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_gpio_out_value parameter: + * gpio: GPIO1, GPIO2, GPIO3 or GPIO4 + * value: LOW or HIGH + */ +int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) +{ + int status; + unsigned defgpio; + + if (!the_tps) + return -ENODEV; + if ((gpio < GPIO1) || (gpio > GPIO4)) + return -EINVAL; + + down(&the_tps->lock); + + defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO); + + /* Configure GPIO for output */ + defgpio |= 1 << (gpio + 3); + + /* Writing 1 forces a logic 0 on that GPIO and vice versa */ + switch (value) { + case LOW: + defgpio |= 1 << (gpio - 1); /* set GPIO low by writing 1 */ + break; + /* case HIGH: */ + default: + defgpio &= ~(1 << (gpio - 1)); /* set GPIO high by writing 0 */ + break; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_DEFGPIO, defgpio); + + pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME, + gpio, value ? "high" : "low", + i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO)); + + up(&the_tps->lock); + return status; +} +EXPORT_SYMBOL(tps65010_set_gpio_out_value); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_led parameter: + * led: LED1 or LED2 + * mode: ON, OFF or BLINK + */ +int tps65010_set_led(unsigned led, unsigned mode) +{ + int status; + unsigned led_on, led_per, offs; + + if (!the_tps) + return -ENODEV; + + if(led == LED1) + offs = 0; + else { + offs = 2; + led = LED2; + } + + down(&the_tps->lock); + + dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); + + dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); + + switch (mode) { + case OFF: + led_on = 1 << 7; + led_per = 0 << 7; + break; + case ON: + led_on = 1 << 7; + led_per = 1 << 7; + break; + case BLINK: + led_on = 0x30 | (0 << 7); + led_per = 0x08 | (1 << 7); + break; + default: + printk(KERN_ERR "%s: Wrong mode parameter for tps65010_set_led()\n", + DRIVER_NAME); + up(&the_tps->lock); + return -EINVAL; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_LED1_ON + offs, led_on); + + if (status != 0) { + printk(KERN_ERR "%s: Failed to write led%i_on register\n", + DRIVER_NAME, led); + up(&the_tps->lock); + return status; + } + + dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_LED1_PER + offs, led_per); + + if (status != 0) { + printk(KERN_ERR "%s: Failed to write led%i_per register\n", + DRIVER_NAME, led); + up(&the_tps->lock); + return status; + } + + dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65010_set_led); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_vib parameter: + * value: ON or OFF + */ +int tps65010_set_vib(unsigned value) +{ + int status; + unsigned vdcdc2; + + if (!the_tps) + return -ENODEV; + + down(&the_tps->lock); + + vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2); + vdcdc2 &= ~(1 << 1); + if (value) + vdcdc2 |= (1 << 1); + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VDCDC2, vdcdc2); + + pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off"); + + up(&the_tps->lock); + return status; +} +EXPORT_SYMBOL(tps65010_set_vib); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_low_pwr parameter: + * mode: ON or OFF + */ +int tps65010_set_low_pwr(unsigned mode) +{ + int status; + unsigned vdcdc1; + + if (!the_tps) + return -ENODEV; + + down(&the_tps->lock); + + pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME, + mode ? "enable" : "disable", + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); + + switch (mode) { + case OFF: + vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ + break; + /* case ON: */ + default: + vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ + break; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VDCDC1, vdcdc1); + + if (status != 0) + printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", + DRIVER_NAME); + else + pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65010_set_low_pwr); + +/*-------------------------------------------------------------------------*/ +/* tps65010_config_vregs1 parameter: + * value to be written to VREGS1 register + * Note: The complete register is written, set all bits you need + */ +int tps65010_config_vregs1(unsigned value) +{ + int status; + + if (!the_tps) + return -ENODEV; + + down(&the_tps->lock); + + pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VREGS1, value); + + if (status != 0) + printk(KERN_ERR "%s: Failed to write vregs1 register\n", + DRIVER_NAME); + else + pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65010_config_vregs1); + +/*-------------------------------------------------------------------------*/ +/* tps65013_set_low_pwr parameter: + * mode: ON or OFF + */ + +/* FIXME: Assumes AC or USB power is present. Setting AUA bit is not + required if power supply is through a battery */ + +int tps65013_set_low_pwr(unsigned mode) +{ + int status; + unsigned vdcdc1, chgconfig; + + if (!the_tps || the_tps->por) + return -ENODEV; + + down(&the_tps->lock); + + pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n", + DRIVER_NAME, + mode ? "enable" : "disable", + i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG), + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); + vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); + + switch (mode) { + case OFF: + chgconfig &= ~TPS65013_AUA; /* disable AUA bit */ + vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ + break; + /* case ON: */ + default: + chgconfig |= TPS65013_AUA; /* enable AUA bit */ + vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ + break; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_CHGCONFIG, chgconfig); + if (status != 0) { + printk(KERN_ERR "%s: Failed to write chconfig register\n", + DRIVER_NAME); + up(&the_tps->lock); + return status; + } + + chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); + the_tps->chgconf = chgconfig; + show_chgconfig(0, "chgconf", chgconfig); + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VDCDC1, vdcdc1); + + if (status != 0) + printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", + DRIVER_NAME); + else + pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65013_set_low_pwr); + +/*-------------------------------------------------------------------------*/ + +static int __init tps_init(void) +{ + u32 tries = 3; + int status = -ENODEV; + + printk(KERN_INFO "%s: version %s\n", DRIVER_NAME, DRIVER_VERSION); + + /* some boards have startup glitches */ + while (tries--) { + status = i2c_add_driver(&tps65010_driver); + if (the_tps) + break; + i2c_del_driver(&tps65010_driver); + if (!tries) { + printk(KERN_ERR "%s: no chip?\n", DRIVER_NAME); + return -ENODEV; + } + pr_debug("%s: re-probe ...\n", DRIVER_NAME); + msleep(10); + } + +#if defined(CONFIG_ARM) + if (machine_is_omap_osk()) { + + // FIXME: More should be placed in the initialization code + // of the submodules (DSP, ethernet, power management, + // board-osk.c). Careful: I2C is initialized "late". + + /* Let LED1 (D9) blink */ + tps65010_set_led(LED1, BLINK); + + /* Disable LED 2 (D2) */ + tps65010_set_led(LED2, OFF); + + /* Set GPIO 1 HIGH to disable VBUS power supply; + * OHCI driver powers it up/down as needed. + */ + tps65010_set_gpio_out_value(GPIO1, HIGH); + + /* Set GPIO 2 low to turn on LED D3 */ + tps65010_set_gpio_out_value(GPIO2, HIGH); + + /* Set GPIO 3 low to take ethernet out of reset */ + tps65010_set_gpio_out_value(GPIO3, LOW); + + /* gpio4 for VDD_DSP */ + + /* Enable LOW_PWR */ + tps65010_set_low_pwr(ON); + + /* Switch VLDO2 to 3.0V for AIC23 */ + tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE); + + } else if (machine_is_omap_h2()) { + /* gpio3 for SD, gpio4 for VDD_DSP */ + + /* Enable LOW_PWR */ + tps65010_set_low_pwr(ON); + } else if (machine_is_omap_h3()) { + /* gpio4 for SD, gpio3 for VDD_DSP */ +#ifdef CONFIG_PM + /* Enable LOW_PWR */ + tps65013_set_low_pwr(ON); +#endif + } +#endif + + return status; +} +/* NOTE: this MUST be initialized before the other parts of the system + * that rely on it ... but after the i2c bus on which this relies. + * That is, much earlier than on PC-type systems, which don't often use + * I2C as a core system bus. + */ +subsys_initcall(tps_init); + +static void __exit tps_exit(void) +{ + i2c_del_driver(&tps65010_driver); +} +module_exit(tps_exit); + diff --git a/include/asm-arm/arch-omap/tps65010.h b/include/asm-arm/arch-omap/tps65010.h index 0f97bb2..b9aa2b3 100644 --- a/include/asm-arm/arch-omap/tps65010.h +++ b/include/asm-arm/arch-omap/tps65010.h @@ -30,6 +30,66 @@ /* * ---------------------------------------------------------------------------- + * Registers, all 8 bits + * ---------------------------------------------------------------------------- + */ + +#define TPS_CHGSTATUS 0x01 +# define TPS_CHG_USB (1 << 7) +# define TPS_CHG_AC (1 << 6) +# define TPS_CHG_THERM (1 << 5) +# define TPS_CHG_TERM (1 << 4) +# define TPS_CHG_TAPER_TMO (1 << 3) +# define TPS_CHG_CHG_TMO (1 << 2) +# define TPS_CHG_PRECHG_TMO (1 << 1) +# define TPS_CHG_TEMP_ERR (1 << 0) +#define TPS_REGSTATUS 0x02 +# define TPS_REG_ONOFF (1 << 7) +# define TPS_REG_COVER (1 << 6) +# define TPS_REG_UVLO (1 << 5) +# define TPS_REG_NO_CHG (1 << 4) /* tps65013 */ +# define TPS_REG_PG_LD02 (1 << 3) +# define TPS_REG_PG_LD01 (1 << 2) +# define TPS_REG_PG_MAIN (1 << 1) +# define TPS_REG_PG_CORE (1 << 0) +#define TPS_MASK1 0x03 +#define TPS_MASK2 0x04 +#define TPS_ACKINT1 0x05 +#define TPS_ACKINT2 0x06 +#define TPS_CHGCONFIG 0x07 +# define TPS_CHARGE_POR (1 << 7) /* 65010/65012 */ +# define TPS65013_AUA (1 << 7) /* 65011/65013 */ +# define TPS_CHARGE_RESET (1 << 6) +# define TPS_CHARGE_FAST (1 << 5) +# define TPS_CHARGE_CURRENT (3 << 3) +# define TPS_VBUS_500MA (1 << 2) +# define TPS_VBUS_CHARGING (1 << 1) +# define TPS_CHARGE_ENABLE (1 << 0) +#define TPS_LED1_ON 0x08 +#define TPS_LED1_PER 0x09 +#define TPS_LED2_ON 0x0a +#define TPS_LED2_PER 0x0b +#define TPS_VDCDC1 0x0c +# define TPS_ENABLE_LP (1 << 3) +#define TPS_VDCDC2 0x0d +#define TPS_VREGS1 0x0e +# define TPS_LDO2_ENABLE (1 << 7) +# define TPS_LDO2_OFF (1 << 6) +# define TPS_VLDO2_3_0V (3 << 4) +# define TPS_VLDO2_2_75V (2 << 4) +# define TPS_VLDO2_2_5V (1 << 4) +# define TPS_VLDO2_1_8V (0 << 4) +# define TPS_LDO1_ENABLE (1 << 3) +# define TPS_LDO1_OFF (1 << 2) +# define TPS_VLDO1_3_0V (3 << 0) +# define TPS_VLDO1_2_75V (2 << 0) +# define TPS_VLDO1_2_5V (1 << 0) +# define TPS_VLDO1_ADJ (0 << 0) +#define TPS_MASK3 0x0f +#define TPS_DEFGPIO 0x10 + +/* + * ---------------------------------------------------------------------------- * Macros used by exported functions * ---------------------------------------------------------------------------- */ @@ -71,10 +131,26 @@ extern int tps65010_set_gpio_out_value(unsigned gpio, unsigned value); */ extern int tps65010_set_led(unsigned led, unsigned mode); +/* tps65010_set_vib parameter: + * value: ON or OFF + */ +extern int tps65010_set_vib(unsigned value); + /* tps65010_set_low_pwr parameter: * mode: ON or OFF */ extern int tps65010_set_low_pwr(unsigned mode); +/* tps65010_config_vregs1 parameter: + * value to be written to VREGS1 register + * Note: The complete register is written, set all bits you need + */ +extern int tps65010_config_vregs1(unsigned value); + +/* tps65013_set_low_pwr parameter: + * mode: ON or OFF + */ +extern int tps65013_set_low_pwr(unsigned mode); + #endif /* __ASM_ARCH_TPS65010_H */ -- cgit v0.10.2 From 2bf34a1ca9d570dd4fab4d95c4de82d873ecf718 Mon Sep 17 00:00:00 2001 From: "R.Marek@sh.cvut.cz" Date: Thu, 26 May 2005 12:42:11 +0000 Subject: [PATCH] I2C: documentation update 1/3 This patch just changes the extension of Documentation/i2c/chips/smsc47b397.txt to none - to conform with naming in i2c subsystem directory. Signed-off-by: Rudolf Marek Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/i2c/chips/smsc47b397 b/Documentation/i2c/chips/smsc47b397 new file mode 100644 index 0000000..4737bb6 --- /dev/null +++ b/Documentation/i2c/chips/smsc47b397 @@ -0,0 +1,146 @@ +November 23, 2004 + +The following specification describes the SMSC LPC47B397-NC sensor chip +(for which there is no public datasheet available). This document was +provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected +by Mark M. Hoffman . + +* * * * * + +Methods for detecting the HP SIO and reading the thermal data on a dc7100. + +The thermal information on the dc7100 is contained in the SIO Hardware Monitor +(HWM). The information is accessed through an index/data pair. The index/data +pair is located at the HWM Base Address + 0 and the HWM Base Address + 1. The +HWM Base address can be obtained from Logical Device 8, registers 0x60 (MSB) +and 0x61 (LSB). Currently we are using 0x480 for the HWM Base Address and +0x480 and 0x481 for the index/data pair. + +Reading temperature information. +The temperature information is located in the following registers: +Temp1 0x25 (Currently, this reflects the CPU temp on all systems). +Temp2 0x26 +Temp3 0x27 +Temp4 0x80 + +Programming Example +The following is an example of how to read the HWM temperature registers: +MOV DX,480H +MOV AX,25H +OUT DX,AL +MOV DX,481H +IN AL,DX + +AL contains the data in hex, the temperature in Celsius is the decimal +equivalent. + +Ex: If AL contains 0x2A, the temperature is 42 degrees C. + +Reading tach information. +The fan speed information is located in the following registers: + LSB MSB +Tach1 0x28 0x29 (Currently, this reflects the CPU + fan speed on all systems). +Tach2 0x2A 0x2B +Tach3 0x2C 0x2D +Tach4 0x2E 0x2F + +Important!!! +Reading the tach LSB locks the tach MSB. +The LSB Must be read first. + +How to convert the tach reading to RPM. +The tach reading (TCount) is given by: (Tach MSB * 256) + (Tach LSB) +The SIO counts the number of 90kHz (11.111us) pulses per revolution. +RPM = 60/(TCount * 11.111us) + +Example: +Reg 0x28 = 0x9B +Reg 0x29 = 0x08 + +TCount = 0x89B = 2203 + +RPM = 60 / (2203 * 11.11111 E-6) = 2451 RPM + +Obtaining the SIO version. + +CONFIGURATION SEQUENCE +To program the configuration registers, the following sequence must be followed: +1. Enter Configuration Mode +2. Configure the Configuration Registers +3. Exit Configuration Mode. + +Enter Configuration Mode +To place the chip into the Configuration State The config key (0x55) is written +to the CONFIG PORT (0x2E). + +Configuration Mode +In configuration mode, the INDEX PORT is located at the CONFIG PORT address and +the DATA PORT is at INDEX PORT address + 1. + +The desired configuration registers are accessed in two steps: +a. Write the index of the Logical Device Number Configuration Register + (i.e., 0x07) to the INDEX PORT and then write the number of the + desired logical device to the DATA PORT. + +b. Write the address of the desired configuration register within the + logical device to the INDEX PORT and then write or read the config- + uration register through the DATA PORT. + +Note: If accessing the Global Configuration Registers, step (a) is not required. + +Exit Configuration Mode +To exit the Configuration State the write 0xAA to the CONFIG PORT (0x2E). +The chip returns to the RUN State. (This is important). + +Programming Example +The following is an example of how to read the SIO Device ID located at 0x20 + +; ENTER CONFIGURATION MODE +MOV DX,02EH +MOV AX,055H +OUT DX,AL +; GLOBAL CONFIGURATION REGISTER +MOV DX,02EH +MOV AL,20H +OUT DX,AL +; READ THE DATA +MOV DX,02FH +IN AL,DX +; EXIT CONFIGURATION MODE +MOV DX,02EH +MOV AX,0AAH +OUT DX,AL + +The registers of interest for identifying the SIO on the dc7100 are Device ID +(0x20) and Device Rev (0x21). + +The Device ID will read 0X6F +The Device Rev currently reads 0x01 + +Obtaining the HWM Base Address. +The following is an example of how to read the HWM Base Address located in +Logical Device 8. + +; ENTER CONFIGURATION MODE +MOV DX,02EH +MOV AX,055H +OUT DX,AL +; CONFIGURE REGISTER CRE0, +; LOGICAL DEVICE 8 +MOV DX,02EH +MOV AL,07H +OUT DX,AL ;Point to LD# Config Reg +MOV DX,02FH +MOV AL, 08H +OUT DX,AL;Point to Logical Device 8 +; +MOV DX,02EH +MOV AL,60H +OUT DX,AL ; Point to HWM Base Addr MSB +MOV DX,02FH +IN AL,DX ; Get MSB of HWM Base Addr +; EXIT CONFIGURATION MODE +MOV DX,02EH +MOV AX,0AAH +OUT DX,AL diff --git a/Documentation/i2c/chips/smsc47b397.txt b/Documentation/i2c/chips/smsc47b397.txt deleted file mode 100644 index 389edae..0000000 --- a/Documentation/i2c/chips/smsc47b397.txt +++ /dev/null @@ -1,146 +0,0 @@ -November 23, 2004 - -The following specification describes the SMSC LPC47B397-NC sensor chip -(for which there is no public datasheet available). This document was -provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected -by Mark M. Hoffman . - -* * * * * - -Methods for detecting the HP SIO and reading the thermal data on a dc7100. - -The thermal information on the dc7100 is contained in the SIO Hardware Monitor -(HWM). The information is accessed through an index/data pair. The index/data -pair is located at the HWM Base Address + 0 and the HWM Base Address + 1. The -HWM Base address can be obtained from Logical Device 8, registers 0x60 (MSB) -and 0x61 (LSB). Currently we are using 0x480 for the HWM Base Address and -0x480 and 0x481 for the index/data pair. - -Reading temperature information. -The temperature information is located in the following registers: -Temp1 0x25 (Currently, this reflects the CPU temp on all systems). -Temp2 0x26 -Temp3 0x27 -Temp4 0x80 - -Programming Example -The following is an example of how to read the HWM temperature registers: -MOV DX,480H -MOV AX,25H -OUT DX,AL -MOV DX,481H -IN AL,DX - -AL contains the data in hex, the temperature in Celsius is the decimal -equivalent. - -Ex: If AL contains 0x2A, the temperature is 42 degrees C. - -Reading tach information. -The fan speed information is located in the following registers: - LSB MSB -Tach1 0x28 0x29 (Currently, this reflects the CPU - fan speed on all systems). -Tach2 0x2A 0x2B -Tach3 0x2C 0x2D -Tach4 0x2E 0x2F - -Important!!! -Reading the tach LSB locks the tach MSB. -The LSB Must be read first. - -How to convert the tach reading to RPM. -The tach reading (TCount) is given by: (Tach MSB * 256) + (Tach LSB) -The SIO counts the number of 90kHz (11.111us) pulses per revolution. -RPM = 60/(TCount * 11.111us) - -Example: -Reg 0x28 = 0x9B -Reg 0x29 = 0x08 - -TCount = 0x89B = 2203 - -RPM = 60 / (2203 * 11.11111 E-6) = 2451 RPM - -Obtaining the SIO version. - -CONFIGURATION SEQUENCE -To program the configuration registers, the following sequence must be followed: -1. Enter Configuration Mode -2. Configure the Configuration Registers -3. Exit Configuration Mode. - -Enter Configuration Mode -To place the chip into the Configuration State The config key (0x55) is written -to the CONFIG PORT (0x2E). - -Configuration Mode -In configuration mode, the INDEX PORT is located at the CONFIG PORT address and -the DATA PORT is at INDEX PORT address + 1. - -The desired configuration registers are accessed in two steps: -a. Write the index of the Logical Device Number Configuration Register - (i.e., 0x07) to the INDEX PORT and then write the number of the - desired logical device to the DATA PORT. - -b. Write the address of the desired configuration register within the - logical device to the INDEX PORT and then write or read the config- - uration register through the DATA PORT. - -Note: If accessing the Global Configuration Registers, step (a) is not required. - -Exit Configuration Mode -To exit the Configuration State the write 0xAA to the CONFIG PORT (0x2E). -The chip returns to the RUN State. (This is important). - -Programming Example -The following is an example of how to read the SIO Device ID located at 0x20 - -; ENTER CONFIGURATION MODE -MOV DX,02EH -MOV AX,055H -OUT DX,AL -; GLOBAL CONFIGURATION REGISTER -MOV DX,02EH -MOV AL,20H -OUT DX,AL -; READ THE DATA -MOV DX,02FH -IN AL,DX -; EXIT CONFIGURATION MODE -MOV DX,02EH -MOV AX,0AAH -OUT DX,AL - -The registers of interest for identifying the SIO on the dc7100 are Device ID -(0x20) and Device Rev (0x21). - -The Device ID will read 0X6F -The Device Rev currently reads 0x01 - -Obtaining the HWM Base Address. -The following is an example of how to read the HWM Base Address located in -Logical Device 8. - -; ENTER CONFIGURATION MODE -MOV DX,02EH -MOV AX,055H -OUT DX,AL -; CONFIGURE REGISTER CRE0, -; LOGICAL DEVICE 8 -MOV DX,02EH -MOV AL,07H -OUT DX,AL ;Point to LD# Config Reg -MOV DX,02FH -MOV AL, 08H -OUT DX,AL;Point to Logical Device 8 -; -MOV DX,02EH -MOV AL,60H -OUT DX,AL ; Point to HWM Base Addr MSB -MOV DX,02FH -IN AL,DX ; Get MSB of HWM Base Addr -; EXIT CONFIGURATION MODE -MOV DX,02EH -MOV AX,0AAH -OUT DX,AL -- cgit v0.10.2 From 7f15b66468b7003d5241e352a007e73be5519b20 Mon Sep 17 00:00:00 2001 From: "R.Marek@sh.cvut.cz" Date: Thu, 26 May 2005 12:42:19 +0000 Subject: [PATCH] I2C: documentation update 2/3 This patch adds missing documentation for system health monitoring chips. I would like to thank all people, who helped me with this project. Signed-off-by: Rudolf Marek Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/i2c/chips/adm1021 b/Documentation/i2c/chips/adm1021 new file mode 100644 index 0000000..03d02bf --- /dev/null +++ b/Documentation/i2c/chips/adm1021 @@ -0,0 +1,111 @@ +Kernel driver adm1021 +===================== + +Supported chips: + * Analog Devices ADM1021 + Prefix: 'adm1021' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Analog Devices website + * Analog Devices ADM1021A/ADM1023 + Prefix: 'adm1023' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Analog Devices website + * Genesys Logic GL523SM + Prefix: 'gl523sm' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: + * Intel Xeon Processor + Prefix: - any other - may require 'force_adm1021' parameter + Addresses scanned: none + Datasheet: Publicly available at Intel website + * Maxim MAX1617 + Prefix: 'max1617' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Maxim website + * Maxim MAX1617A + Prefix: 'max1617a' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Maxim website + * National Semiconductor LM84 + Prefix: 'lm84' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the National Semiconductor website + * Philips NE1617 + Prefix: 'max1617' (probably detected as a max1617) + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Philips website + * Philips NE1617A + Prefix: 'max1617' (probably detected as a max1617) + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Philips website + * TI THMC10 + Prefix: 'thmc10' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the TI website + * Onsemi MC1066 + Prefix: 'mc1066' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Onsemi website + + +Authors: + Frodo Looijaard , + Philip Edelbrock + +Module Parameters +----------------- + +* read_only: int + Don't set any values, read only mode + + +Description +----------- + +The chips supported by this driver are very similar. The Maxim MAX1617 is +the oldest; it has the problem that it is not very well detectable. The +MAX1617A solves that. The ADM1021 is a straight clone of the MAX1617A. +Ditto for the THMC10. From here on, we will refer to all these chips as +ADM1021-clones. + +The ADM1021 and MAX1617A reports a die code, which is a sort of revision +code. This can help us pinpoint problems; it is not very useful +otherwise. + +ADM1021-clones implement two temperature sensors. One of them is internal, +and measures the temperature of the chip itself; the other is external and +is realised in the form of a transistor-like device. A special alarm +indicates whether the remote sensor is connected. + +Each sensor has its own low and high limits. When they are crossed, the +corresponding alarm is set and remains on as long as the temperature stays +out of range. Temperatures are measured in degrees Celsius. Measurements +are possible between -65 and +127 degrees, with a resolution of one degree. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may already +have disappeared! + +This driver only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. It is possible to make +ADM1021-clones do faster measurements, but there is really no good reason +for that. + +Xeon support +------------ + +Some Xeon processors have real max1617, adm1021, or compatible chips +within them, with two temperature sensors. + +Other Xeons have chips with only one sensor. + +If you have a Xeon, and the adm1021 module loads, and both temperatures +appear valid, then things are good. + +If the adm1021 module doesn't load, you should try this: + modprobe adm1021 force_adm1021=BUS,ADDRESS + ADDRESS can only be 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. + +If you have dual Xeons you may have appear to have two separate +adm1021-compatible chips, or two single-temperature sensors, at distinct +addresses. diff --git a/Documentation/i2c/chips/adm1025 b/Documentation/i2c/chips/adm1025 new file mode 100644 index 0000000..39d2b78 --- /dev/null +++ b/Documentation/i2c/chips/adm1025 @@ -0,0 +1,51 @@ +Kernel driver adm1025 +===================== + +Supported chips: + * Analog Devices ADM1025, ADM1025A + Prefix: 'adm1025' + Addresses scanned: I2C 0x2c - 0x2e + Datasheet: Publicly available at the Analog Devices website + * Philips NE1619 + Prefix: 'ne1619' + Addresses scanned: I2C 0x2c - 0x2d + Datasheet: Publicly available at the Philips website + +The NE1619 presents some differences with the original ADM1025: + * Only two possible addresses (0x2c - 0x2d). + * No temperature offset register, but we don't use it anyway. + * No INT mode for pin 16. We don't play with it anyway. + +Authors: + Chen-Yuan Wu , + Jean Delvare + +Description +----------- + +(This is from Analog Devices.) The ADM1025 is a complete system hardware +monitor for microprocessor-based systems, providing measurement and limit +comparison of various system parameters. Five voltage measurement inputs +are provided, for monitoring +2.5V, +3.3V, +5V and +12V power supplies and +the processor core voltage. The ADM1025 can monitor a sixth power-supply +voltage by measuring its own VCC. One input (two pins) is dedicated to a +remote temperature-sensing diode and an on-chip temperature sensor allows +ambient temperature to be monitored. + +One specificity of this chip is that the pin 11 can be hardwired in two +different manners. It can act as the +12V power-supply voltage analog +input, or as the a fifth digital entry for the VID reading (bit 4). It's +kind of strange since both are useful, and the reason for designing the +chip that way is obscure at least to me. The bit 5 of the configuration +register can be used to define how the chip is hardwired. Please note that +it is not a choice you have to make as the user. The choice was already +made by your motherboard's maker. If the configuration bit isn't set +properly, you'll have a wrong +12V reading or a wrong VID reading. The way +the driver handles that is to preserve this bit through the initialization +process, assuming that the BIOS set it up properly beforehand. If it turns +out not to be true in some cases, we'll provide a module parameter to force +modes. + +This driver also supports the ADM1025A, which differs from the ADM1025 +only in that it has "open-drain VID inputs while the ADM1025 has on-chip +100k pull-ups on the VID inputs". It doesn't make any difference for us. diff --git a/Documentation/i2c/chips/adm1026 b/Documentation/i2c/chips/adm1026 new file mode 100644 index 0000000..473c689 --- /dev/null +++ b/Documentation/i2c/chips/adm1026 @@ -0,0 +1,93 @@ +Kernel driver adm1026 +===================== + +Supported chips: + * Analog Devices ADM1026 + Prefix: 'adm1026' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: Publicly available at the Analog Devices website + http://www.analog.com/en/prod/0,,766_825_ADM1026,00.html + +Authors: + Philip Pokorny for Penguin Computing + Justin Thiessen + +Module Parameters +----------------- + +* gpio_input: int array (min = 1, max = 17) + List of GPIO pins (0-16) to program as inputs +* gpio_output: int array (min = 1, max = 17) + List of GPIO pins (0-16) to program as outputs +* gpio_inverted: int array (min = 1, max = 17) + List of GPIO pins (0-16) to program as inverted +* gpio_normal: int array (min = 1, max = 17) + List of GPIO pins (0-16) to program as normal/non-inverted +* gpio_fan: int array (min = 1, max = 8) + List of GPIO pins (0-7) to program as fan tachs + + +Description +----------- + +This driver implements support for the Analog Devices ADM1026. Analog +Devices calls it a "complete thermal system management controller." + +The ADM1026 implements three (3) temperature sensors, 17 voltage sensors, +16 general purpose digital I/O lines, eight (8) fan speed sensors (8-bit), +an analog output and a PWM output along with limit, alarm and mask bits for +all of the above. There is even 8k bytes of EEPROM memory on chip. + +Temperatures are measured in degrees Celsius. There are two external +sensor inputs and one internal sensor. Each sensor has a high and low +limit. If the limit is exceeded, an interrupt (#SMBALERT) can be +generated. The interrupts can be masked. In addition, there are over-temp +limits for each sensor. If this limit is exceeded, the #THERM output will +be asserted. The current temperature and limits have a resolution of 1 +degree. + +Fan rotation speeds are reported in RPM (rotations per minute) but measured +in counts of a 22.5kHz internal clock. Each fan has a high limit which +corresponds to a minimum fan speed. If the limit is exceeded, an interrupt +can be generated. Each fan can be programmed to divide the reference clock +by 1, 2, 4 or 8. Not all RPM values can accurately be represented, so some +rounding is done. With a divider of 8, the slowest measurable speed of a +two pulse per revolution fan is 661 RPM. + +There are 17 voltage sensors. An alarm is triggered if the voltage has +crossed a programmable minimum or maximum limit. Note that minimum in this +case always means 'closest to zero'; this is important for negative voltage +measurements. Several inputs have integrated attenuators so they can measure +higher voltages directly. 3.3V, 5V, 12V, -12V and battery voltage all have +dedicated inputs. There are several inputs scaled to 0-3V full-scale range +for SCSI terminator power. The remaining inputs are not scaled and have +a 0-2.5V full-scale range. A 2.5V or 1.82V reference voltage is provided +for negative voltage measurements. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may already +have disappeared! Note that in the current implementation, all hardware +registers are read whenever any data is read (unless it is less than 2.0 +seconds since the last update). This means that you can easily miss +once-only alarms. + +The ADM1026 measures continuously. Analog inputs are measured about 4 +times a second. Fan speed measurement time depends on fan speed and +divisor. It can take as long as 1.5 seconds to measure all fan speeds. + +The ADM1026 has the ability to automatically control fan speed based on the +temperature sensor inputs. Both the PWM output and the DAC output can be +used to control fan speed. Usually only one of these two outputs will be +used. Write the minimum PWM or DAC value to the appropriate control +register. Then set the low temperature limit in the tmin values for each +temperature sensor. The range of control is fixed at 20 °C, and the +largest difference between current and tmin of the temperature sensors sets +the control output. See the datasheet for several example circuits for +controlling fan speed with the PWM and DAC outputs. The fan speed sensors +do not have PWM compensation, so it is probably best to control the fan +voltage from the power lead rather than on the ground lead. + +The datasheet shows an example application with VID signals attached to +GPIO lines. Unfortunately, the chip may not be connected to the VID lines +in this way. The driver assumes that the chips *is* connected this way to +get a VID voltage. diff --git a/Documentation/i2c/chips/adm1031 b/Documentation/i2c/chips/adm1031 new file mode 100644 index 0000000..130a383 --- /dev/null +++ b/Documentation/i2c/chips/adm1031 @@ -0,0 +1,35 @@ +Kernel driver adm1031 +===================== + +Supported chips: + * Analog Devices ADM1030 + Prefix: 'adm1030' + Addresses scanned: I2C 0x2c to 0x2e + Datasheet: Publicly available at the Analog Devices website + http://products.analog.com/products/info.asp?product=ADM1030 + + * Analog Devices ADM1031 + Prefix: 'adm1031' + Addresses scanned: I2C 0x2c to 0x2e + Datasheet: Publicly available at the Analog Devices website + http://products.analog.com/products/info.asp?product=ADM1031 + +Authors: + Alexandre d'Alton + Jean Delvare + +Description +----------- + +The ADM1030 and ADM1031 are digital temperature sensors and fan controllers. +They sense their own temperature as well as the temperature of up to one +(ADM1030) or two (ADM1031) external diodes. + +All temperature values are given in degrees Celsius. Resolution is 0.5 +degree for the local temperature, 0.125 degree for the remote temperatures. + +Each temperature channel has its own high and low limits, plus a critical +limit. + +The ADM1030 monitors a single fan speed, while the ADM1031 monitors up to +two. Each fan channel has its own low speed limit. diff --git a/Documentation/i2c/chips/asb100 b/Documentation/i2c/chips/asb100 new file mode 100644 index 0000000..ab7365e --- /dev/null +++ b/Documentation/i2c/chips/asb100 @@ -0,0 +1,72 @@ +Kernel driver asb100 +==================== + +Supported Chips: + * Asus ASB100 and ASB100-A "Bach" + Prefix: 'asb100' + Addresses scanned: I2C 0x2d + Datasheet: none released + +Author: Mark M. Hoffman + +Description +----------- + +This driver implements support for the Asus ASB100 and ASB100-A "Bach". +These are custom ASICs available only on Asus mainboards. Asus refuses to +supply a datasheet for these chips. Thanks go to many people who helped +investigate their hardware, including: + +Vitaly V. Bursov +Alexander van Kaam (author of MBM for Windows) +Bertrik Sikken + +The ASB100 implements seven voltage sensors, three fan rotation speed +sensors, four temperature sensors, VID lines and alarms. In addition to +these, the ASB100-A also implements a single PWM controller for fans 2 and +3 (i.e. one setting controls both.) If you have a plain ASB100, the PWM +controller will simply not work (or maybe it will for you... it doesn't for +me). + +Temperatures are measured and reported in degrees Celsius. + +Fan speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. + +Voltage sensors (also known as IN sensors) report values in volts. + +The VID lines encode the core voltage value: the voltage level your +processor should work with. This is hardcoded by the mainboard and/or +processor itself. It is a value in volts. + +Alarms: (TODO question marks indicate may or may not work) + +0x0001 => in0 (?) +0x0002 => in1 (?) +0x0004 => in2 +0x0008 => in3 +0x0010 => temp1 (1) +0x0020 => temp2 +0x0040 => fan1 +0x0080 => fan2 +0x0100 => in4 +0x0200 => in5 (?) (2) +0x0400 => in6 (?) (2) +0x0800 => fan3 +0x1000 => chassis switch +0x2000 => temp3 + +Alarm Notes: + +(1) This alarm will only trigger if the hysteresis value is 127C. +I.e. it behaves the same as w83781d. + +(2) The min and max registers for these values appear to +be read-only or otherwise stuck at 0x00. + +TODO: +* Experiment with fan divisors > 8. +* Experiment with temp. sensor types. +* Are there really 13 voltage inputs? Probably not... +* Cleanups, no doubt... + diff --git a/Documentation/i2c/chips/ds1621 b/Documentation/i2c/chips/ds1621 new file mode 100644 index 0000000..1fee6f1 --- /dev/null +++ b/Documentation/i2c/chips/ds1621 @@ -0,0 +1,108 @@ +Kernel driver ds1621 +==================== + +Supported chips: + * Dallas Semiconductor DS1621 + Prefix: 'ds1621' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Dallas Semiconductor website + http://www.dalsemi.com/ + * Dallas Semiconductor DS1625 + Prefix: 'ds1621' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Dallas Semiconductor website + http://www.dalsemi.com/ + +Authors: + Christian W. Zuckschwerdt + valuable contributions by Jan M. Sendler + ported to 2.6 by Aurelien Jarno + with the help of Jean Delvare + +Module Parameters +------------------ + +* polarity int + Output's polarity: 0 = active high, 1 = active low + +Description +----------- + +The DS1621 is a (one instance) digital thermometer and thermostat. It has +both high and low temperature limits which can be user defined (i.e. +programmed into non-volatile on-chip registers). Temperature range is -55 +degree Celsius to +125 in 0.5 increments. You may convert this into a +Fahrenheit range of -67 to +257 degrees with 0.9 steps. If polarity +parameter is not provided, original value is used. + +As for the thermostat, behavior can also be programmed using the polarity +toggle. On the one hand ("heater"), the thermostat output of the chip, +Tout, will trigger when the low limit temperature is met or underrun and +stays high until the high limit is met or exceeded. On the other hand +("cooler"), vice versa. That way "heater" equals "active low", whereas +"conditioner" equals "active high". Please note that the DS1621 data sheet +is somewhat misleading in this point since setting the polarity bit does +not simply invert Tout. + +A second thing is that, during extensive testing, Tout showed a tolerance +of up to +/- 0.5 degrees even when compared against precise temperature +readings. Be sure to have a high vs. low temperature limit gap of al least +1.0 degree Celsius to avoid Tout "bouncing", though! + +As for alarms, you can read the alarm status of the DS1621 via the 'alarms' +/sys file interface. The result consists mainly of bit 6 and 5 of the +configuration register of the chip; bit 6 (0x40 or 64) is the high alarm +bit and bit 5 (0x20 or 32) the low one. These bits are set when the high or +low limits are met or exceeded and are reset by the module as soon as the +respective temperature ranges are left. + +The alarm registers are in no way suitable to find out about the actual +status of Tout. They will only tell you about its history, whether or not +any of the limits have ever been met or exceeded since last power-up or +reset. Be aware: When testing, it showed that the status of Tout can change +with neither of the alarms set. + +Temperature conversion of the DS1621 takes up to 1000ms; internal access to +non-volatile registers may last for 10ms or below. + +High Accuracy Temperature Reading +--------------------------------- + +As said before, the temperature issued via the 9-bit i2c-bus data is +somewhat arbitrary. Internally, the temperature conversion is of a +different kind that is explained (not so...) well in the DS1621 data sheet. +To cut the long story short: Inside the DS1621 there are two oscillators, +both of them biassed by a temperature coefficient. + +Higher resolution of the temperature reading can be achieved using the +internal projection, which means taking account of REG_COUNT and REG_SLOPE +(the driver manages them): + +Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature +Resolution on the DS1620' and App Note 105: 'High Resolution Temperature +Measurement with Dallas Direct-to-Digital Temperature Sensors' + +- Read the 9-bit temperature and strip the LSB (Truncate the .5 degs) +- The resulting value is TEMP_READ. +- Then, read REG_COUNT. +- And then, REG_SLOPE. + + TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE) + +Note that this is what the DONE bit in the DS1621 configuration register is +good for: Internally, one temperature conversion takes up to 1000ms. Before +that conversion is complete you will not be able to read valid things out +of REG_COUNT and REG_SLOPE. The DONE bit, as you may have guessed by now, +tells you whether the conversion is complete ("done", in plain English) and +thus, whether the values you read are good or not. + +The DS1621 has two modes of operation: "Continuous" conversion, which can +be understood as the default stand-alone mode where the chip gets the +temperature and controls external devices via its Tout pin or tells other +i2c's about it if they care. The other mode is called "1SHOT", that means +that it only figures out about the temperature when it is explicitly told +to do so; this can be seen as power saving mode. + +Now if you want to read REG_COUNT and REG_SLOPE, you have to either stop +the continuous conversions until the contents of these registers are valid, +or, in 1SHOT mode, you have to have one conversion made. diff --git a/Documentation/i2c/chips/eeprom b/Documentation/i2c/chips/eeprom new file mode 100644 index 0000000..f7e8104 --- /dev/null +++ b/Documentation/i2c/chips/eeprom @@ -0,0 +1,96 @@ +Kernel driver eeprom +==================== + +Supported chips: + * Any EEPROM chip in the designated address range + Prefix: 'eeprom' + Addresses scanned: I2C 0x50 - 0x57 + Datasheets: Publicly available from: + Atmel (www.atmel.com), + Catalyst (www.catsemi.com), + Fairchild (www.fairchildsemi.com), + Microchip (www.microchip.com), + Philips (www.semiconductor.philips.com), + Rohm (www.rohm.com), + ST (www.st.com), + Xicor (www.xicor.com), + and others. + + Chip Size (bits) Address + 24C01 1K 0x50 (shadows at 0x51 - 0x57) + 24C01A 1K 0x50 - 0x57 (Typical device on DIMMs) + 24C02 2K 0x50 - 0x57 + 24C04 4K 0x50, 0x52, 0x54, 0x56 + (additional data at 0x51, 0x53, 0x55, 0x57) + 24C08 8K 0x50, 0x54 (additional data at 0x51, 0x52, + 0x53, 0x55, 0x56, 0x57) + 24C16 16K 0x50 (additional data at 0x51 - 0x57) + Sony 2K 0x57 + + Atmel 34C02B 2K 0x50 - 0x57, SW write protect at 0x30-37 + Catalyst 34FC02 2K 0x50 - 0x57, SW write protect at 0x30-37 + Catalyst 34RC02 2K 0x50 - 0x57, SW write protect at 0x30-37 + Fairchild 34W02 2K 0x50 - 0x57, SW write protect at 0x30-37 + Microchip 24AA52 2K 0x50 - 0x57, SW write protect at 0x30-37 + ST M34C02 2K 0x50 - 0x57, SW write protect at 0x30-37 + + +Authors: + Frodo Looijaard , + Philip Edelbrock , + Jean Delvare , + Greg Kroah-Hartman , + IBM Corp. + +Description +----------- + +This is a simple EEPROM module meant to enable reading the first 256 bytes +of an EEPROM (on a SDRAM DIMM for example). However, it will access serial +EEPROMs on any I2C adapter. The supported devices are generically called +24Cxx, and are listed above; however the numbering for these +industry-standard devices may vary by manufacturer. + +This module was a programming exercise to get used to the new project +organization laid out by Frodo, but it should be at least completely +effective for decoding the contents of EEPROMs on DIMMs. + +DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants. +The other devices will not be found on a DIMM because they respond to more +than one address. + +DDC Monitors may contain any device. Often a 24C01, which responds to all 8 +addresses, is found. + +Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the +specification, so it is guess work and far from being complete. + +The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional +software write protect register at 0x30 - 0x37 (0x20 less than the memory +location). The chip responds to "write quick" detection at this address but +does not respond to byte reads. If this register is present, the lower 128 +bytes of the memory array are not write protected. Any byte data write to +this address will write protect the memory array permanently, and the +device will no longer respond at the 0x30-37 address. The eeprom driver +does not support this register. + +Lacking functionality: + +* Full support for larger devices (24C04, 24C08, 24C16). These are not +typically found on a PC. These devices will appear as separate devices at +multiple addresses. + +* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512). +These devices require two-byte address fields and are not supported. + +* Enable Writing. Again, no technical reason why not, but making it easy +to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy +to disable the DIMMs (potentially preventing the computer from booting) +until the values are restored somehow. + +Use: + +After inserting the module (and any other required SMBus/i2c modules), you +should have some EEPROM directories in /sys/bus/i2c/devices/* of names such +as "0-0050". Inside each of these is a series of files, the eeprom file +contains the binary data from EEPROM. diff --git a/Documentation/i2c/chips/fscher b/Documentation/i2c/chips/fscher new file mode 100644 index 0000000..6403165 --- /dev/null +++ b/Documentation/i2c/chips/fscher @@ -0,0 +1,169 @@ +Kernel driver fscher +==================== + +Supported chips: + * Fujitsu-Siemens Hermes chip + Prefix: 'fscher' + Addresses scanned: I2C 0x73 + +Authors: + Reinhard Nissl based on work + from Hermann Jung , + Frodo Looijaard , + Philip Edelbrock + +Description +----------- + +This driver implements support for the Fujitsu-Siemens Hermes chip. It is +described in the 'Register Set Specification BMC Hermes based Systemboard' +from Fujitsu-Siemens. + +The Hermes chip implements a hardware-based system management, e.g. for +controlling fan speed and core voltage. There is also a watchdog counter on +the chip which can trigger an alarm and even shut the system down. + +The chip provides three temperature values (CPU, motherboard and +auxiliary), three voltage values (+12V, +5V and battery) and three fans +(power supply, CPU and auxiliary). + +Temperatures are measured in degrees Celsius. The resolution is 1 degree. + +Fan rotation speeds are reported in RPM (rotations per minute). The value +can be divided by a programmable divider (1, 2 or 4) which is stored on +the chip. + +Voltage sensors (also known as "in" sensors) report their values in volts. + +All values are reported as final values from the driver. There is no need +for further calculations. + + +Detailed description +-------------------- + +Below you'll find a single line description of all the bit values. With +this information, you're able to decode e. g. alarms, wdog, etc. To make +use of the watchdog, you'll need to set the watchdog time and enable the +watchdog. After that it is necessary to restart the watchdog time within +the specified period of time, or a system reset will occur. + +* revision + READING & 0xff = 0x??: HERMES revision identification + +* alarms + READING & 0x80 = 0x80: CPU throttling active + READING & 0x80 = 0x00: CPU running at full speed + + READING & 0x10 = 0x10: software event (see control:1) + READING & 0x10 = 0x00: no software event + + READING & 0x08 = 0x08: watchdog event (see wdog:2) + READING & 0x08 = 0x00: no watchdog event + + READING & 0x02 = 0x02: thermal event (see temp*:1) + READING & 0x02 = 0x00: no thermal event + + READING & 0x01 = 0x01: fan event (see fan*:1) + READING & 0x01 = 0x00: no fan event + + READING & 0x13 ! 0x00: ALERT LED is flashing + +* control + READING & 0x01 = 0x01: software event + READING & 0x01 = 0x00: no software event + + WRITING & 0x01 = 0x01: set software event + WRITING & 0x01 = 0x00: clear software event + +* watchdog_control + READING & 0x80 = 0x80: power off on watchdog event while thermal event + READING & 0x80 = 0x00: watchdog power off disabled (just system reset enabled) + + READING & 0x40 = 0x40: watchdog timebase 60 seconds (see also wdog:1) + READING & 0x40 = 0x00: watchdog timebase 2 seconds + + READING & 0x10 = 0x10: watchdog enabled + READING & 0x10 = 0x00: watchdog disabled + + WRITING & 0x80 = 0x80: enable "power off on watchdog event while thermal event" + WRITING & 0x80 = 0x00: disable "power off on watchdog event while thermal event" + + WRITING & 0x40 = 0x40: set watchdog timebase to 60 seconds + WRITING & 0x40 = 0x00: set watchdog timebase to 2 seconds + + WRITING & 0x20 = 0x20: disable watchdog + + WRITING & 0x10 = 0x10: enable watchdog / restart watchdog time + +* watchdog_state + READING & 0x02 = 0x02: watchdog system reset occurred + READING & 0x02 = 0x00: no watchdog system reset occurred + + WRITING & 0x02 = 0x02: clear watchdog event + +* watchdog_preset + READING & 0xff = 0x??: configured watch dog time in units (see wdog:3 0x40) + + WRITING & 0xff = 0x??: configure watch dog time in units + +* in* (0: +5V, 1: +12V, 2: onboard 3V battery) + READING: actual voltage value + +* temp*_status (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor) + READING & 0x02 = 0x02: thermal event (overtemperature) + READING & 0x02 = 0x00: no thermal event + + READING & 0x01 = 0x01: sensor is working + READING & 0x01 = 0x00: sensor is faulty + + WRITING & 0x02 = 0x02: clear thermal event + +* temp*_input (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor) + READING: actual temperature value + +* fan*_status (1: power supply fan, 2: CPU fan, 3: auxiliary fan) + READING & 0x04 = 0x04: fan event (fan fault) + READING & 0x04 = 0x00: no fan event + + WRITING & 0x04 = 0x04: clear fan event + +* fan*_div (1: power supply fan, 2: CPU fan, 3: auxiliary fan) + Divisors 2,4 and 8 are supported, both for reading and writing + +* fan*_pwm (1: power supply fan, 2: CPU fan, 3: auxiliary fan) + READING & 0xff = 0x00: fan may be switched off + READING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V) + READING & 0xff = 0xff: fan must run at maximum speed (supply: 12V) + READING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V) + + WRITING & 0xff = 0x00: fan may be switched off + WRITING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V) + WRITING & 0xff = 0xff: fan must run at maximum speed (supply: 12V) + WRITING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V) + +* fan*_input (1: power supply fan, 2: CPU fan, 3: auxiliary fan) + READING: actual RPM value + + +Limitations +----------- + +* Measuring fan speed +It seems that the chip counts "ripples" (typical fans produce 2 ripples per +rotation while VERAX fans produce 18) in a 9-bit register. This register is +read out every second, then the ripple prescaler (2, 4 or 8) is applied and +the result is stored in the 8 bit output register. Due to the limitation of +the counting register to 9 bits, it is impossible to measure a VERAX fan +properly (even with a prescaler of 8). At its maximum speed of 3500 RPM the +fan produces 1080 ripples per second which causes the counting register to +overflow twice, leading to only 186 RPM. + +* Measuring input voltages +in2 ("battery") reports the voltage of the onboard lithium battery and not ++3.3V from the power supply. + +* Undocumented features +Fujitsu-Siemens Computers has not documented all features of the chip so +far. Their software, System Guard, shows that there are a still some +features which cannot be controlled by this implementation. diff --git a/Documentation/i2c/chips/gl518sm b/Documentation/i2c/chips/gl518sm new file mode 100644 index 0000000..ce08818 --- /dev/null +++ b/Documentation/i2c/chips/gl518sm @@ -0,0 +1,74 @@ +Kernel driver gl518sm +===================== + +Supported chips: + * Genesys Logic GL518SM release 0x00 + Prefix: 'gl518sm' + Addresses scanned: I2C 0x2c and 0x2d + Datasheet: http://www.genesyslogic.com/pdf + * Genesys Logic GL518SM release 0x80 + Prefix: 'gl518sm' + Addresses scanned: I2C 0x2c and 0x2d + Datasheet: http://www.genesyslogic.com/pdf + +Authors: + Frodo Looijaard , + Kyösti Mälkki + Hong-Gunn Chew + Jean Delvare + +Description +----------- + +IMPORTANT: + +For the revision 0x00 chip, the in0, in1, and in2 values (+5V, +3V, +and +12V) CANNOT be read. This is a limitation of the chip, not the driver. + +This driver supports the Genesys Logic GL518SM chip. There are at least +two revision of this chip, which we call revision 0x00 and 0x80. Revision +0x80 chips support the reading of all voltages and revision 0x00 only +for VIN3. + +The GL518SM implements one temperature sensor, two fan rotation speed +sensors, and four voltage sensors. It can report alarms through the +computer speakers. + +Temperatures are measured in degrees Celsius. An alarm goes off while the +temperature is above the over temperature limit, and has not yet dropped +below the hysteresis limit. The alarm always reflects the current +situation. Measurements are guaranteed between -10 degrees and +110 +degrees, with a accuracy of +/-3 degrees. + +Rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. In +case when you have selected to turn fan1 off, no fan1 alarm is triggered. + +Fan readings can be divided by a programmable divider (1, 2, 4 or 8) to +give the readings more range or accuracy. Not all RPM values can +accurately be represented, so some rounding is done. With a divider +of 2, the lowest representable value is around 1900 RPM. + +Voltage sensors (also known as VIN sensors) report their values in volts. +An alarm is triggered if the voltage has crossed a programmable minimum or +maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. The VDD input +measures voltages between 0.000 and 5.865 volt, with a resolution of 0.023 +volt. The other inputs measure voltages between 0.000 and 4.845 volt, with +a resolution of 0.019 volt. Note that revision 0x00 chips do not support +reading the current voltage of any input except for VIN3; limit setting and +alarms work fine, though. + +When an alarm is triggered, you can be warned by a beeping signal through your +computer speaker. It is possible to enable all beeping globally, or only the +beeping for some alarms. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once (except for temperature alarms). This means that the +cause for the alarm may already have disappeared! Note that in the current +implementation, all hardware registers are read whenever any data is read +(unless it is less than 1.5 seconds since the last update). This means that +you can easily miss once-only alarms. + +The GL518SM only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. diff --git a/Documentation/i2c/chips/it87 b/Documentation/i2c/chips/it87 new file mode 100644 index 0000000..0d01950 --- /dev/null +++ b/Documentation/i2c/chips/it87 @@ -0,0 +1,96 @@ +Kernel driver it87 +================== + +Supported chips: + * IT8705F + Prefix: 'it87' + Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports) + Datasheet: Publicly available at the ITE website + http://www.ite.com.tw/ + * IT8712F + Prefix: 'it8712' + Addresses scanned: I2C 0x28 - 0x2f + from Super I/O config space, or default ISA 0x290 (8 I/O ports) + Datasheet: Publicly available at the ITE website + http://www.ite.com.tw/ + * SiS950 [clone of IT8705F] + Prefix: 'sis950' + Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports) + Datasheet: No longer be available + +Author: Christophe Gauthron + + +Module Parameters +----------------- + +* update_vbat: int + + 0 if vbat should report power on value, 1 if vbat should be updated after + each read. Default is 0. On some boards the battery voltage is provided + by either the battery or the onboard power supply. Only the first reading + at power on will be the actual battery voltage (which the chip does + automatically). On other boards the battery voltage is always fed to + the chip so can be read at any time. Excessive reading may decrease + battery life but no information is given in the datasheet. + +* fix_pwm_polarity int + + Force PWM polarity to active high (DANGEROUS). Some chips are + misconfigured by BIOS - PWM values would be inverted. This option tries + to fix this. Please contact your BIOS manufacturer and ask him for fix. + +Description +----------- + +This driver implements support for the IT8705F, IT8712F and SiS950 chips. + +This driver also supports IT8712F, which adds SMBus access, and a VID +input, used to report the Vcore voltage of the Pentium processor. +The IT8712F additionally features VID inputs. + +These chips are 'Super I/O chips', supporting floppy disks, infrared ports, +joysticks and other miscellaneous stuff. For hardware monitoring, they +include an 'environment controller' with 3 temperature sensors, 3 fan +rotation speed sensors, 8 voltage sensors, and associated alarms. + +Temperatures are measured in degrees Celsius. An alarm is triggered once +when the Overtemperature Shutdown limit is crossed. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give the +readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. An +alarm is triggered if the voltage has crossed a programmable minimum or +maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. All voltage +inputs can measure voltages between 0 and 4.08 volts, with a resolution of +0.016 volt. The battery voltage in8 does not have limit registers. + +The VID lines (IT8712F only) encode the core voltage value: the voltage +level your processor should work with. This is hardcoded by the mainboard +and/or processor itself. It is a value in volts. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may already +have disappeared! Note that in the current implementation, all hardware +registers are read whenever any data is read (unless it is less than 1.5 +seconds since the last update). This means that you can easily miss +once-only alarms. + +The IT87xx only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. + +To change sensor N to a thermistor, 'echo 2 > tempN_type' where N is 1, 2, +or 3. To change sensor N to a thermal diode, 'echo 3 > tempN_type'. +Give 0 for unused sensor. Any other value is invalid. To configure this at +startup, consult lm_sensors's /etc/sensors.conf. (2 = thermistor; +3 = thermal diode) + +The fan speed control features are limited to manual PWM mode. Automatic +"Smart Guardian" mode control handling is not implemented. However +if you want to go for "manual mode" just write 1 to pwmN_enable. diff --git a/Documentation/i2c/chips/lm63 b/Documentation/i2c/chips/lm63 new file mode 100644 index 0000000..31660bf --- /dev/null +++ b/Documentation/i2c/chips/lm63 @@ -0,0 +1,57 @@ +Kernel driver lm63 +================== + +Supported chips: + * National Semiconductor LM63 + Prefix: 'lm63' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM63.html + +Author: Jean Delvare + +Thanks go to Tyan and especially Alex Buckingham for setting up a remote +access to their S4882 test platform for this driver. + http://www.tyan.com/ + +Description +----------- + +The LM63 is a digital temperature sensor with integrated fan monitoring +and control. + +The LM63 is basically an LM86 with fan speed monitoring and control +capabilities added. It misses some of the LM86 features though: + - No low limit for local temperature. + - No critical limit for local temperature. + - Critical limit for remote temperature can be changed only once. We + will consider that the critical limit is read-only. + +The datasheet isn't very clear about what the tachometer reading is. + +An explanation from National Semiconductor: The two lower bits of the read +value have to be masked out. The value is still 16 bit in width. + +All temperature values are given in degrees Celsius. Resolution is 1.0 +degree for the local temperature, 0.125 degree for the remote temperature. + +The fan speed is measured using a tachometer. Contrary to most chips which +store the value in an 8-bit register and have a selectable clock divider +to make sure that the result will fit in the register, the LM63 uses 16-bit +value for measuring the speed of the fan. It can measure fan speeds down to +83 RPM, at least in theory. + +Note that the pin used for fan monitoring is shared with an alert out +function. Depending on how the board designer wanted to use the chip, fan +speed monitoring will or will not be possible. The proper chip configuration +is left to the BIOS, and the driver will blindly trust it. + +A PWM output can be used to control the speed of the fan. The LM63 has two +PWM modes: manual and automatic. Automatic mode is not fully implemented yet +(you cannot define your custom PWM/temperature curve), and mode change isn't +supported either. + +The lm63 driver will not update its values more frequently than every +second; reading them more often will do no harm, but will return 'old' +values. + diff --git a/Documentation/i2c/chips/lm75 b/Documentation/i2c/chips/lm75 new file mode 100644 index 0000000..8e6356f --- /dev/null +++ b/Documentation/i2c/chips/lm75 @@ -0,0 +1,65 @@ +Kernel driver lm75 +================== + +Supported chips: + * National Semiconductor LM75 + Prefix: 'lm75' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + * Dallas Semiconductor DS75 + Prefix: 'lm75' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Dallas Semiconductor website + http://www.maxim-ic.com/ + * Dallas Semiconductor DS1775 + Prefix: 'lm75' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Dallas Semiconductor website + http://www.maxim-ic.com/ + * Maxim MAX6625, MAX6626 + Prefix: 'lm75' + Addresses scanned: I2C 0x48 - 0x4b + Datasheet: Publicly available at the Maxim website + http://www.maxim-ic.com/ + * Microchip (TelCom) TCN75 + Prefix: 'lm75' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Microchip website + http://www.microchip.com/ + +Author: Frodo Looijaard + +Description +----------- + +The LM75 implements one temperature sensor. Limits can be set through the +Overtemperature Shutdown register and Hysteresis register. Each value can be +set and read to half-degree accuracy. +An alarm is issued (usually to a connected LM78) when the temperature +gets higher then the Overtemperature Shutdown value; it stays on until +the temperature falls below the Hysteresis value. +All temperatures are in degrees Celsius, and are guaranteed within a +range of -55 to +125 degrees. + +The LM75 only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. + +The LM75 is usually used in combination with LM78-like chips, to measure +the temperature of the processor(s). + +The DS75, DS1775, MAX6625, and MAX6626 are supported as well. +They are not distinguished from an LM75. While most of these chips +have three additional bits of accuracy (12 vs. 9 for the LM75), +the additional bits are not supported. Not only that, but these chips will +not be detected if not in 9-bit precision mode (use the force parameter if +needed). + +The TCN75 is supported as well, and is not distinguished from an LM75. + +The LM75 is essentially an industry standard; there may be other +LM75 clones not listed here, with or without various enhancements, +that are supported. + +The LM77 is not supported, contrary to what we pretended for a long time. +Both chips are simply not compatible, value encoding differs. diff --git a/Documentation/i2c/chips/lm77 b/Documentation/i2c/chips/lm77 new file mode 100644 index 0000000..57c3a46 --- /dev/null +++ b/Documentation/i2c/chips/lm77 @@ -0,0 +1,22 @@ +Kernel driver lm77 +================== + +Supported chips: + * National Semiconductor LM77 + Prefix: 'lm77' + Addresses scanned: I2C 0x48 - 0x4b + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + +Author: Andras BALI + +Description +----------- + +The LM77 implements one temperature sensor. The temperature +sensor incorporates a band-gap type temperature sensor, +10-bit ADC, and a digital comparator with user-programmable upper +and lower limit values. + +Limits can be set through the Overtemperature Shutdown register and +Hysteresis register. diff --git a/Documentation/i2c/chips/lm78 b/Documentation/i2c/chips/lm78 new file mode 100644 index 0000000..357086e --- /dev/null +++ b/Documentation/i2c/chips/lm78 @@ -0,0 +1,82 @@ +Kernel driver lm78 +================== + +Supported chips: + * National Semiconductor LM78 + Prefix: 'lm78' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + * National Semiconductor LM78-J + Prefix: 'lm78-j' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + * National Semiconductor LM79 + Prefix: 'lm79' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + +Author: Frodo Looijaard + +Description +----------- + +This driver implements support for the National Semiconductor LM78, LM78-J +and LM79. They are described as 'Microprocessor System Hardware Monitors'. + +There is almost no difference between the three supported chips. Functionally, +the LM78 and LM78-J are exactly identical. The LM79 has one more VID line, +which is used to report the lower voltages newer Pentium processors use. +From here on, LM7* means either of these three types. + +The LM7* implements one temperature sensor, three fan rotation speed sensors, +seven voltage sensors, VID lines, alarms, and some miscellaneous stuff. + +Temperatures are measured in degrees Celsius. An alarm is triggered once +when the Overtemperature Shutdown limit is crossed; it is triggered again +as soon as it drops below the Hysteresis value. A more useful behavior +can be found by setting the Hysteresis value to +127 degrees Celsius; in +this case, alarms are issued during all the time when the actual temperature +is above the Overtemperature Shutdown value. Measurements are guaranteed +between -55 and +125 degrees, with a resolution of 1 degree. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. All voltage +inputs can measure voltages between 0 and 4.08 volts, with a resolution +of 0.016 volt. + +The VID lines encode the core voltage value: the voltage level your processor +should work with. This is hardcoded by the mainboard and/or processor itself. +It is a value in volts. When it is unconnected, you will often find the +value 3.50 V here. + +In addition to the alarms described above, there are a couple of additional +ones. There is a BTI alarm, which gets triggered when an external chip has +crossed its limits. Usually, this is connected to all LM75 chips; if at +least one crosses its limits, this bit gets set. The CHAS alarm triggers +if your computer case is open. The FIFO alarms should never trigger; it +indicates an internal error. The SMI_IN alarm indicates some other chip +has triggered an SMI interrupt. As we do not use SMI interrupts at all, +this condition usually indicates there is a problem with some other +device. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 1.5 seconds since the last update). This means that you can easily +miss once-only alarms. + +The LM7* only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. diff --git a/Documentation/i2c/chips/lm80 b/Documentation/i2c/chips/lm80 new file mode 100644 index 0000000..cb5b407 --- /dev/null +++ b/Documentation/i2c/chips/lm80 @@ -0,0 +1,56 @@ +Kernel driver lm80 +================== + +Supported chips: + * National Semiconductor LM80 + Prefix: 'lm80' + Addresses scanned: I2C 0x28 - 0x2f + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + +Authors: + Frodo Looijaard , + Philip Edelbrock + +Description +----------- + +This driver implements support for the National Semiconductor LM80. +It is described as a 'Serial Interface ACPI-Compatible Microprocessor +System Hardware Monitor'. + +The LM80 implements one temperature sensor, two fan rotation speed sensors, +seven voltage sensors, alarms, and some miscellaneous stuff. + +Temperatures are measured in degrees Celsius. There are two sets of limits +which operate independently. When the HOT Temperature Limit is crossed, +this will cause an alarm that will be reasserted until the temperature +drops below the HOT Hysteresis. The Overtemperature Shutdown (OS) limits +should work in the same way (but this must be checked; the datasheet +is unclear about this). Measurements are guaranteed between -55 and ++125 degrees. The current temperature measurement has a resolution of +0.0625 degrees; the limits have a resolution of 1 degree. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. All voltage +inputs can measure voltages between 0 and 2.55 volts, with a resolution +of 0.01 volt. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 2.0 seconds since the last update). This means that you can easily +miss once-only alarms. + +The LM80 only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. diff --git a/Documentation/i2c/chips/lm83 b/Documentation/i2c/chips/lm83 new file mode 100644 index 0000000..061d9ed --- /dev/null +++ b/Documentation/i2c/chips/lm83 @@ -0,0 +1,76 @@ +Kernel driver lm83 +================== + +Supported chips: + * National Semiconductor LM83 + Prefix: 'lm83' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM83.html + + +Author: Jean Delvare + +Description +----------- + +The LM83 is a digital temperature sensor. It senses its own temperature as +well as the temperature of up to three external diodes. It is compatible +with many other devices such as the LM84 and all other ADM1021 clones. +The main difference between the LM83 and the LM84 in that the later can +only sense the temperature of one external diode. + +Using the adm1021 driver for a LM83 should work, but only two temperatures +will be reported instead of four. + +The LM83 is only found on a handful of motherboards. Both a confirmed +list and an unconfirmed list follow. If you can confirm or infirm the +fact that any of these motherboards do actually have an LM83, please +contact us. Note that the LM90 can easily be misdetected as a LM83. + +Confirmed motherboards: + SBS P014 + +Unconfirmed motherboards: + Gigabyte GA-8IK1100 + Iwill MPX2 + Soltek SL-75DRV5 + +The driver has been successfully tested by Magnus Forsström, who I'd +like to thank here. More testers will be of course welcome. + +The fact that the LM83 is only scarcely used can be easily explained. +Most motherboards come with more than just temperature sensors for +health monitoring. They also have voltage and fan rotation speed +sensors. This means that temperature-only chips are usually used as +secondary chips coupled with another chip such as an IT8705F or similar +chip, which provides more features. Since systems usually need three +temperature sensors (motherboard, processor, power supply) and primary +chips provide some temperature sensors, the secondary chip, if needed, +won't have to handle more than two temperatures. Thus, ADM1021 clones +are sufficient, and there is no need for a four temperatures sensor +chip such as the LM83. The only case where using an LM83 would make +sense is on SMP systems, such as the above-mentioned Iwill MPX2, +because you want an additional temperature sensor for each additional +CPU. + +On the SBS P014, this is different, since the LM83 is the only hardware +monitoring chipset. One temperature sensor is used for the motherboard +(actually measuring the LM83's own temperature), one is used for the +CPU. The two other sensors must be used to measure the temperature of +two other points of the motherboard. We suspect these points to be the +north and south bridges, but this couldn't be confirmed. + +All temperature values are given in degrees Celsius. Local temperature +is given within a range of 0 to +85 degrees. Remote temperatures are +given within a range of 0 to +125 degrees. Resolution is 1.0 degree, +accuracy is guaranteed to 3.0 degrees (see the datasheet for more +details). + +Each sensor has its own high limit, but the critical limit is common to +all four sensors. There is no hysteresis mechanism as found on most +recent temperature sensors. + +The lm83 driver will not update its values more frequently than every +other second; reading them more often will do no harm, but will return +'old' values. diff --git a/Documentation/i2c/chips/lm85 b/Documentation/i2c/chips/lm85 new file mode 100644 index 0000000..9549237 --- /dev/null +++ b/Documentation/i2c/chips/lm85 @@ -0,0 +1,221 @@ +Kernel driver lm85 +================== + +Supported chips: + * National Semiconductor LM85 (B and C versions) + Prefix: 'lm85' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: http://www.national.com/pf/LM/LM85.html + * Analog Devices ADM1027 + Prefix: 'adm1027' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: http://www.analog.com/en/prod/0,,766_825_ADM1027,00.html + * Analog Devices ADT7463 + Prefix: 'adt7463' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: http://www.analog.com/en/prod/0,,766_825_ADT7463,00.html + * SMSC EMC6D100, SMSC EMC6D101 + Prefix: 'emc6d100' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: http://www.smsc.com/main/tools/discontinued/6d100.pdf + * SMSC EMC6D102 + Prefix: 'emc6d102' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: http://www.smsc.com/main/catalog/emc6d102.html + +Authors: + Philip Pokorny , + Frodo Looijaard , + Richard Barrington , + Margit Schubert-While , + Justin Thiessen + +Description +----------- + +This driver implements support for the National Semiconductor LM85 and +compatible chips including the Analog Devices ADM1027, ADT7463 and +SMSC EMC6D10x chips family. + +The LM85 uses the 2-wire interface compatible with the SMBUS 2.0 +specification. Using an analog to digital converter it measures three (3) +temperatures and five (5) voltages. It has four (4) 16-bit counters for +measuring fan speed. Five (5) digital inputs are provided for sampling the +VID signals from the processor to the VRM. Lastly, there are three (3) PWM +outputs that can be used to control fan speed. + +The voltage inputs have internal scaling resistors so that the following +voltage can be measured without external resistors: + + 2.5V, 3.3V, 5V, 12V, and CPU core voltage (2.25V) + +The temperatures measured are one internal diode, and two remote diodes. +Remote 1 is generally the CPU temperature. These inputs are designed to +measure a thermal diode like the one in a Pentium 4 processor in a socket +423 or socket 478 package. They can also measure temperature using a +transistor like the 2N3904. + +A sophisticated control system for the PWM outputs is designed into the +LM85 that allows fan speed to be adjusted automatically based on any of the +three temperature sensors. Each PWM output is individually adjustable and +programmable. Once configured, the LM85 will adjust the PWM outputs in +response to the measured temperatures without further host intervention. +This feature can also be disabled for manual control of the PWM's. + +Each of the measured inputs (voltage, temperature, fan speed) has +corresponding high/low limit values. The LM85 will signal an ALARM if any +measured value exceeds either limit. + +The LM85 samples all inputs continuously. The lm85 driver will not read +the registers more often than once a second. Further, configuration data is +only read once each 5 minutes. There is twice as much config data as +measurements, so this would seem to be a worthwhile optimization. + +Special Features +---------------- + +The LM85 has four fan speed monitoring modes. The ADM1027 has only two. +Both have special circuitry to compensate for PWM interactions with the +TACH signal from the fans. The ADM1027 can be configured to measure the +speed of a two wire fan, but the input conditioning circuitry is different +for 3-wire and 2-wire mode. For this reason, the 2-wire fan modes are not +exposed to user control. The BIOS should initialize them to the correct +mode. If you've designed your own ADM1027, you'll have to modify the +init_client function and add an insmod parameter to set this up. + +To smooth the response of fans to changes in temperature, the LM85 has an +optional filter for smoothing temperatures. The ADM1027 has the same +config option but uses it to rate limit the changes to fan speed instead. + +The ADM1027 and ADT7463 have a 10-bit ADC and can therefore measure +temperatures with 0.25 degC resolution. They also provide an offset to the +temperature readings that is automatically applied during measurement. +This offset can be used to zero out any errors due to traces and placement. +The documentation says that the offset is in 0.25 degC steps, but in +initial testing of the ADM1027 it was 1.00 degC steps. Analog Devices has +confirmed this "bug". The ADT7463 is reported to work as described in the +documentation. The current lm85 driver does not show the offset register. + +The ADT7463 has a THERM asserted counter. This counter has a 22.76ms +resolution and a range of 5.8 seconds. The driver implements a 32-bit +accumulator of the counter value to extend the range to over a year. The +counter will stay at it's max value until read. + +See the vendor datasheets for more information. There is application note +from National (AN-1260) with some additional information about the LM85. +The Analog Devices datasheet is very detailed and describes a procedure for +determining an optimal configuration for the automatic PWM control. + +The SMSC EMC6D100 & EMC6D101 monitor external voltages, temperatures, and +fan speeds. They use this monitoring capability to alert the system to out +of limit conditions and can automatically control the speeds of multiple +fans in a PC or embedded system. The EMC6D101, available in a 24-pin SSOP +package, and the EMC6D100, available in a 28-pin SSOP package, are designed +to be register compatible. The EMC6D100 offers all the features of the +EMC6D101 plus additional voltage monitoring and system control features. +Unfortunately it is not possible to distinguish between the package +versions on register level so these additional voltage inputs may read +zero. The EMC6D102 features addtional ADC bits thus extending precision +of voltage and temperature channels. + + +Hardware Configurations +----------------------- + +The LM85 can be jumpered for 3 different SMBus addresses. There are +no other hardware configuration options for the LM85. + +The lm85 driver detects both LM85B and LM85C revisions of the chip. See the +datasheet for a complete description of the differences. Other than +identifying the chip, the driver behaves no differently with regard to +these two chips. The LM85B is recommended for new designs. + +The ADM1027 and ADT7463 chips have an optional SMBALERT output that can be +used to signal the chipset in case a limit is exceeded or the temperature +sensors fail. Individual sensor interrupts can be masked so they won't +trigger SMBALERT. The SMBALERT output if configured replaces one of the other +functions (PWM2 or IN0). This functionality is not implemented in current +driver. + +The ADT7463 also has an optional THERM output/input which can be connected +to the processor PROC_HOT output. If available, the autofan control +dynamic Tmin feature can be enabled to keep the system temperature within +spec (just?!) with the least possible fan noise. + +Configuration Notes +------------------- + +Besides standard interfaces driver adds following: + +* Temperatures and Zones + +Each temperature sensor is associated with a Zone. There are three +sensors and therefore three zones (# 1, 2 and 3). Each zone has the following +temperature configuration points: + +* temp#_auto_temp_off - temperature below which fans should be off or spinning very low. +* temp#_auto_temp_min - temperature over which fans start to spin. +* temp#_auto_temp_max - temperature when fans spin at full speed. +* temp#_auto_temp_crit - temperature when all fans will run full speed. + +* PWM Control + +There are three PWM outputs. The LM85 datasheet suggests that the +pwm3 output control both fan3 and fan4. Each PWM can be individually +configured and assigned to a zone for it's control value. Each PWM can be +configured individually according to the following options. + +* pwm#_auto_pwm_min - this specifies the PWM value for temp#_auto_temp_off + temperature. (PWM value from 0 to 255) + +* pwm#_auto_pwm_freq - select base frequency of PWM output. You can select + in range of 10.0 to 94.0 Hz in .1 Hz units. + (Values 100 to 940). + +The pwm#_auto_pwm_freq can be set to one of the following 8 values. Setting the +frequency to a value not on this list, will result in the next higher frequency +being selected. The actual device frequency may vary slightly from this +specification as designed by the manufacturer. Consult the datasheet for more +details. (PWM Frequency values: 100, 150, 230, 300, 380, 470, 620, 940) + +* pwm#_auto_pwm_minctl - this flags selects for temp#_auto_temp_off temperature + the bahaviour of fans. Write 1 to let fans spinning at + pwm#_auto_pwm_min or write 0 to let them off. + +NOTE: It has been reported that there is a bug in the LM85 that causes the flag +to be associated with the zones not the PWMs. This contradicts all the +published documentation. Setting pwm#_min_ctl in this case actually affects all +PWMs controlled by zone '#'. + +* PWM Controlling Zone selection + +* pwm#_auto_channels - controls zone that is associated with PWM + +Configuration choices: + + Value Meaning + ------ ------------------------------------------------ + 1 Controlled by Zone 1 + 2 Controlled by Zone 2 + 3 Controlled by Zone 3 + 23 Controlled by higher temp of Zone 2 or 3 + 123 Controlled by highest temp of Zone 1, 2 or 3 + 0 PWM always 0% (off) + -1 PWM always 100% (full on) + -2 Manual control (write to 'pwm#' to set) + +The National LM85's have two vendor specific configuration +features. Tach. mode and Spinup Control. For more details on these, +see the LM85 datasheet or Application Note AN-1260. + +The Analog Devices ADM1027 has several vendor specific enhancements. +The number of pulses-per-rev of the fans can be set, Tach monitoring +can be optimized for PWM operation, and an offset can be applied to +the temperatures to compensate for systemic errors in the +measurements. + +In addition to the ADM1027 features, the ADT7463 also has Tmin control +and THERM asserted counts. Automatic Tmin control acts to adjust the +Tmin value to maintain the measured temperature sensor at a specified +temperature. There isn't much documentation on this feature in the +ADT7463 data sheet. This is not supported by current driver. diff --git a/Documentation/i2c/chips/lm87 b/Documentation/i2c/chips/lm87 new file mode 100644 index 0000000..c952c57 --- /dev/null +++ b/Documentation/i2c/chips/lm87 @@ -0,0 +1,73 @@ +Kernel driver lm87 +================== + +Supported chips: + * National Semiconductor LM87 + Prefix: 'lm87' + Addresses scanned: I2C 0x2c - 0x2f + Datasheet: http://www.national.com/pf/LM/LM87.html + +Authors: + Frodo Looijaard , + Philip Edelbrock , + Mark Studebaker , + Stephen Rousset , + Dan Eaton , + Jean Delvare , + Original 2.6 port Jeff Oliver + +Description +----------- + +This driver implements support for the National Semiconductor LM87. + +The LM87 implements up to three temperature sensors, up to two fan +rotation speed sensors, up to seven voltage sensors, alarms, and some +miscellaneous stuff. + +Temperatures are measured in degrees Celsius. Each input has a high +and low alarm settings. A high limit produces an alarm when the value +goes above it, and an alarm is also produced when the value goes below +the low limit. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in +volts. An alarm is triggered if the voltage has crossed a programmable +minimum or maximum limit. Note that minimum in this case always means +'closest to zero'; this is important for negative voltage measurements. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 1.0 seconds since the last update). This means that you can easily +miss once-only alarms. + +The lm87 driver only updates its values each 1.0 seconds; reading it more +often will do no harm, but will return 'old' values. + + +Hardware Configurations +----------------------- + +The LM87 has four pins which can serve one of two possible functions, +depending on the hardware configuration. + +Some functions share pins, so not all functions are available at the same +time. Which are depends on the hardware setup. This driver assumes that +the BIOS configured the chip correctly. In that respect, it differs from +the original driver (from lm_sensors for Linux 2.4), which would force the +LM87 to an arbitrary, compile-time chosen mode, regardless of the actual +chipset wiring. + +For reference, here is the list of exclusive functions: + - in0+in5 (default) or temp3 + - fan1 (default) or in6 + - fan2 (default) or in7 + - VID lines (default) or IRQ lines (not handled by this driver) diff --git a/Documentation/i2c/chips/lm90 b/Documentation/i2c/chips/lm90 new file mode 100644 index 0000000..2c4cf39 --- /dev/null +++ b/Documentation/i2c/chips/lm90 @@ -0,0 +1,121 @@ +Kernel driver lm90 +================== + +Supported chips: + * National Semiconductor LM90 + Prefix: 'lm90' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM90.html + * National Semiconductor LM89 + Prefix: 'lm99' + Addresses scanned: I2C 0x4c and 0x4d + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM89.html + * National Semiconductor LM99 + Prefix: 'lm99' + Addresses scanned: I2C 0x4c and 0x4d + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM99.html + * National Semiconductor LM86 + Prefix: 'lm86' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM86.html + * Analog Devices ADM1032 + Prefix: 'adm1032' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the Analog Devices website + http://products.analog.com/products/info.asp?product=ADM1032 + * Analog Devices ADT7461 + Prefix: 'adt7461' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the Analog Devices website + http://products.analog.com/products/info.asp?product=ADT7461 + Note: Only if in ADM1032 compatibility mode + * Maxim MAX6657 + Prefix: 'max6657' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the Maxim website + http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 + * Maxim MAX6658 + Prefix: 'max6657' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the Maxim website + http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 + * Maxim MAX6659 + Prefix: 'max6657' + Addresses scanned: I2C 0x4c, 0x4d (unsupported 0x4e) + Datasheet: Publicly available at the Maxim website + http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 + + +Author: Jean Delvare + + +Description +----------- + +The LM90 is a digital temperature sensor. It senses its own temperature as +well as the temperature of up to one external diode. It is compatible +with many other devices such as the LM86, the LM89, the LM99, the ADM1032, +the MAX6657, MAX6658 and the MAX6659 all of which are supported by this driver. +Note that there is no easy way to differentiate between the last three +variants. The extra address and features of the MAX6659 are not supported by +this driver. Additionally, the ADT7461 is supported if found in ADM1032 +compatibility mode. + +The specificity of this family of chipsets over the ADM1021/LM84 +family is that it features critical limits with hysteresis, and an +increased resolution of the remote temperature measurement. + +The different chipsets of the family are not strictly identical, although +very similar. This driver doesn't handle any specific feature for now, +but could if there ever was a need for it. For reference, here comes a +non-exhaustive list of specific features: + +LM90: + * Filter and alert configuration register at 0xBF. + * ALERT is triggered by temperatures over critical limits. + +LM86 and LM89: + * Same as LM90 + * Better external channel accuracy + +LM99: + * Same as LM89 + * External temperature shifted by 16 degrees down + +ADM1032: + * Consecutive alert register at 0x22. + * Conversion averaging. + * Up to 64 conversions/s. + * ALERT is triggered by open remote sensor. + +ADT7461 + * Extended temperature range (breaks compatibility) + * Lower resolution for remote temperature + +MAX6657 and MAX6658: + * Remote sensor type selection + +MAX6659 + * Selectable address + * Second critical temperature limit + * Remote sensor type selection + +All temperature values are given in degrees Celsius. Resolution +is 1.0 degree for the local temperature, 0.125 degree for the remote +temperature. + +Each sensor has its own high and low limits, plus a critical limit. +Additionally, there is a relative hysteresis value common to both critical +values. To make life easier to user-space applications, two absolute values +are exported, one for each channel, but these values are of course linked. +Only the local hysteresis can be set from user-space, and the same delta +applies to the remote hysteresis. + +The lm90 driver will not update its values more frequently than every +other second; reading them more often will do no harm, but will return +'old' values. + diff --git a/Documentation/i2c/chips/lm92 b/Documentation/i2c/chips/lm92 new file mode 100644 index 0000000..7705bfa --- /dev/null +++ b/Documentation/i2c/chips/lm92 @@ -0,0 +1,37 @@ +Kernel driver lm92 +================== + +Supported chips: + * National Semiconductor LM92 + Prefix: 'lm92' + Addresses scanned: I2C 0x48 - 0x4b + Datasheet: http://www.national.com/pf/LM/LM92.html + * National Semiconductor LM76 + Prefix: 'lm92' + Addresses scanned: none, force parameter needed + Datasheet: http://www.national.com/pf/LM/LM76.html + * Maxim MAX6633/MAX6634/MAX6635 + Prefix: 'lm92' + Addresses scanned: I2C 0x48 - 0x4b + MAX6633 with address in 0x40 - 0x47, 0x4c - 0x4f needs force parameter + and MAX6634 with address in 0x4c - 0x4f needs force parameter + Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074 + +Authors: + Abraham van der Merwe + Jean Delvare + + +Description +----------- + +This driver implements support for the National Semiconductor LM92 +temperature sensor. + +Each LM92 temperature sensor supports a single temperature sensor. There are +alarms for high, low, and critical thresholds. There's also an hysteresis to +control the thresholds for resetting alarms. + +Support was added later for the LM76 and Maxim MAX6633/MAX6634/MAX6635, +which are mostly compatible. They have not all been tested, so you +may need to use the force parameter. diff --git a/Documentation/i2c/chips/max1619 b/Documentation/i2c/chips/max1619 new file mode 100644 index 0000000..d6f8d9c --- /dev/null +++ b/Documentation/i2c/chips/max1619 @@ -0,0 +1,29 @@ +Kernel driver max1619 +===================== + +Supported chips: + * Maxim MAX1619 + Prefix: 'max1619' + Addresses scanned: I2C 0x18-0x1a, 0x29-0x2b, 0x4c-0x4e + Datasheet: Publicly available at the Maxim website + http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf + +Authors: + Alexey Fisher , + Jean Delvare + +Description +----------- + +The MAX1619 is a digital temperature sensor. It senses its own temperature as +well as the temperature of up to one external diode. + +All temperature values are given in degrees Celsius. Resolution +is 1.0 degree for the local temperature and for the remote temperature. + +Only the external sensor has high and low limits. + +The max1619 driver will not update its values more frequently than every +other second; reading them more often will do no harm, but will return +'old' values. + diff --git a/Documentation/i2c/chips/pc87360 b/Documentation/i2c/chips/pc87360 new file mode 100644 index 0000000..89a8fcf --- /dev/null +++ b/Documentation/i2c/chips/pc87360 @@ -0,0 +1,189 @@ +Kernel driver pc87360 +===================== + +Supported chips: + * National Semiconductor PC87360, PC87363, PC87364, PC87365 and PC87366 + Prefixes: 'pc87360', 'pc87363', 'pc87364', 'pc87365', 'pc87366' + Addresses scanned: none, address read from Super I/O config space + Datasheets: + http://www.national.com/pf/PC/PC87360.html + http://www.national.com/pf/PC/PC87363.html + http://www.national.com/pf/PC/PC87364.html + http://www.national.com/pf/PC/PC87365.html + http://www.national.com/pf/PC/PC87366.html + +Authors: Jean Delvare + +Thanks to Sandeep Mehta, Tonko de Rooy and Daniel Ceregatti for testing. +Thanks to Rudolf Marek for helping me investigate conversion issues. + + +Module Parameters +----------------- + +* init int + Chip initialization level: + 0: None + *1: Forcibly enable internal voltage and temperature channels, except in9 + 2: Forcibly enable all voltage and temperature channels, except in9 + 3: Forcibly enable all voltage and temperature channels, including in9 + +Note that this parameter has no effect for the PC87360, PC87363 and PC87364 +chips. + +Also note that for the PC87366, initialization levels 2 and 3 don't enable +all temperature channels, because some of them share pins with each other, +so they can't be used at the same time. + + +Description +----------- + +The National Semiconductor PC87360 Super I/O chip contains monitoring and +PWM control circuitry for two fans. The PC87363 chip is similar, and the +PC87364 chip has monitoring and PWM control for a third fan. + +The National Semiconductor PC87365 and PC87366 Super I/O chips are complete +hardware monitoring chipsets, not only controlling and monitoring three fans, +but also monitoring eleven voltage inputs and two (PC87365) or up to four +(PC87366) temperatures. + + Chip #vin #fan #pwm #temp devid + + PC87360 - 2 2 - 0xE1 + PC87363 - 2 2 - 0xE8 + PC87364 - 3 3 - 0xE4 + PC87365 11 3 3 2 0xE5 + PC87366 11 3 3 3-4 0xE9 + +The driver assumes that no more than one chip is present, and one of the +standard Super I/O addresses is used (0x2E/0x2F or 0x4E/0x4F) + +Fan Monitoring +-------------- + +Fan rotation speeds are reported in RPM (revolutions per minute). An alarm +is triggered if the rotation speed has dropped below a programmable limit. +A different alarm is triggered if the fan speed is too low to be measured. + +Fan readings are affected by a programmable clock divider, giving the +readings more range or accuracy. Usually, users have to learn how it works, +but this driver implements dynamic clock divider selection, so you don't +have to care no more. + +For reference, here are a few values about clock dividers: + + slowest accuracy highest + measurable around 3000 accurate + divider speed (RPM) RPM (RPM) speed (RPM) + 1 1882 18 6928 + 2 941 37 4898 + 4 470 74 3464 + 8 235 150 2449 + +For the curious, here is how the values above were computed: + * slowest measurable speed: clock/(255*divider) + * accuracy around 3000 RPM: 3000^2/clock + * highest accurate speed: sqrt(clock*100) +The clock speed for the PC87360 family is 480 kHz. I arbitrarily chose 100 +RPM as the lowest acceptable accuracy. + +As mentioned above, you don't have to care about this no more. + +Note that not all RPM values can be represented, even when the best clock +divider is selected. This is not only true for the measured speeds, but +also for the programmable low limits, so don't be surprised if you try to +set, say, fan1_min to 2900 and it finally reads 2909. + + +Fan Control +----------- + +PWM (pulse width modulation) values range from 0 to 255, with 0 meaning +that the fan is stopped, and 255 meaning that the fan goes at full speed. + +Be extremely careful when changing PWM values. Low PWM values, even +non-zero, can stop the fan, which may cause irreversible damage to your +hardware if temperature increases too much. When changing PWM values, go +step by step and keep an eye on temperatures. + +One user reported problems with PWM. Changing PWM values would break fan +speed readings. No explanation nor fix could be found. + + +Temperature Monitoring +---------------------- + +Temperatures are reported in degrees Celsius. Each temperature measured has +associated low, high and overtemperature limits, each of which triggers an +alarm when crossed. + +The first two temperature channels are external. The third one (PC87366 +only) is internal. + +The PC87366 has three additional temperature channels, based on +thermistors (as opposed to thermal diodes for the first three temperature +channels). For technical reasons, these channels are held by the VLM +(voltage level monitor) logical device, not the TMS (temperature +measurement) one. As a consequence, these temperatures are exported as +voltages, and converted into temperatures in user-space. + +Note that these three additional channels share their pins with the +external thermal diode channels, so you (physically) can't use them all at +the same time. Although it should be possible to mix the two sensor types, +the documents from National Semiconductor suggest that motherboard +manufacturers should choose one type and stick to it. So you will more +likely have either channels 1 to 3 (thermal diodes) or 3 to 6 (internal +thermal diode, and thermistors). + + +Voltage Monitoring +------------------ + +Voltages are reported relatively to a reference voltage, either internal or +external. Some of them (in7:Vsb, in8:Vdd and in10:AVdd) are divided by two +internally, you will have to compensate in sensors.conf. Others (in0 to in6) +are likely to be divided externally. The meaning of each of these inputs as +well as the values of the resistors used for division is left to the +motherboard manufacturers, so you will have to document yourself and edit +sensors.conf accordingly. National Semiconductor has a document with +recommended resistor values for some voltages, but this still leaves much +room for per motherboard specificities, unfortunately. Even worse, +motherboard manufacturers don't seem to care about National Semiconductor's +recommendations. + +Each voltage measured has associated low and high limits, each of which +triggers an alarm when crossed. + +When available, VID inputs are used to provide the nominal CPU Core voltage. +The driver will default to VRM 9.0, but this can be changed from user-space. +The chipsets can handle two sets of VID inputs (on dual-CPU systems), but +the driver will only export one for now. This may change later if there is +a need. + + +General Remarks +--------------- + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may already +have disappeared! Note that all hardware registers are read whenever any +data is read (unless it is less than 2 seconds since the last update, in +which case cached values are returned instead). As a consequence, when +a once-only alarm triggers, it may take 2 seconds for it to show, and 2 +more seconds for it to disappear. + +Monitoring of in9 isn't enabled at lower init levels (<3) because that +channel measures the battery voltage (Vbat). It is a known fact that +repeatedly sampling the battery voltage reduces its lifetime. National +Semiconductor smartly designed their chipset so that in9 is sampled only +once every 1024 sampling cycles (that is every 34 minutes at the default +sampling rate), so the effect is attenuated, but still present. + + +Limitations +----------- + +The datasheets suggests that some values (fan mins, fan dividers) +shouldn't be changed once the monitoring has started, but we ignore that +recommendation. We'll reconsider if it actually causes trouble. diff --git a/Documentation/i2c/chips/pcf8574 b/Documentation/i2c/chips/pcf8574 new file mode 100644 index 0000000..2752c8c --- /dev/null +++ b/Documentation/i2c/chips/pcf8574 @@ -0,0 +1,69 @@ +Kernel driver pcf8574 +===================== + +Supported chips: + * Philips PCF8574 + Prefix: 'pcf8574' + Addresses scanned: I2C 0x20 - 0x27 + Datasheet: Publicly available at the Philips Semiconductors website + http://www.semiconductors.philips.com/pip/PCF8574P.html + + * Philips PCF8574A + Prefix: 'pcf8574a' + Addresses scanned: I2C 0x38 - 0x3f + Datasheet: Publicly available at the Philips Semiconductors website + http://www.semiconductors.philips.com/pip/PCF8574P.html + +Authors: + Frodo Looijaard , + Philip Edelbrock , + Dan Eaton , + Aurelien Jarno , + Jean Delvare , + + +Description +----------- +The PCF8574(A) is an 8-bit I/O expander for the I2C bus produced by Philips +Semiconductors. It is designed to provide a byte I2C interface to up to 16 +separate devices (8 x PCF8574 and 8 x PCF8574A). + +This device consists of a quasi-bidirectional port. Each of the eight I/Os +can be independently used as an input or output. To setup an I/O as an +input, you have to write a 1 to the corresponding output. + +For more informations see the datasheet. + + +Accessing PCF8574(A) via /sys interface +------------------------------------- + +! Be careful ! +The PCF8574(A) is plainly impossible to detect ! Stupid chip. +So every chip with address in the interval [20..27] and [38..3f] are +detected as PCF8574(A). If you have other chips in this address +range, the workaround is to load this module after the one +for your others chips. + +On detection (i.e. insmod, modprobe et al.), directories are being +created for each detected PCF8574(A): + +/sys/bus/i2c/devices/<0>-<1>/ +where <0> is the bus the chip was detected on (e. g. i2c-0) +and <1> the chip address ([20..27] or [38..3f]): + +(example: /sys/bus/i2c/devices/1-0020/) + +Inside these directories, there are two files each: +read and write (and one file with chip name). + +The read file is read-only. Reading gives you the current I/O input +if the corresponding output is set as 1, otherwise the current output +value, that is to say 0. + +The write file is read/write. Writing a value outputs it on the I/O +port. Reading returns the last written value. + +On module initialization the chip is configured as eight inputs (all +outputs to 1), so you can connect any circuit to the PCF8574(A) without +being afraid of short-circuit. diff --git a/Documentation/i2c/chips/pcf8591 b/Documentation/i2c/chips/pcf8591 new file mode 100644 index 0000000..5628fcf --- /dev/null +++ b/Documentation/i2c/chips/pcf8591 @@ -0,0 +1,90 @@ +Kernel driver pcf8591 +===================== + +Supported chips: + * Philips PCF8591 + Prefix: 'pcf8591' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Philips Semiconductor website + http://www.semiconductors.philips.com/pip/PCF8591P.html + +Authors: + Aurelien Jarno + valuable contributions by Jan M. Sendler , + Jean Delvare + + +Description +----------- +The PCF8591 is an 8-bit A/D and D/A converter (4 analog inputs and one +analog output) for the I2C bus produced by Philips Semiconductors. It +is designed to provide a byte I2C interface to up to 4 separate devices. + +The PCF8591 has 4 analog inputs programmable as single-ended or +differential inputs : +- mode 0 : four single ended inputs + Pins AIN0 to AIN3 are single ended inputs for channels 0 to 3 + +- mode 1 : three differential inputs + Pins AIN3 is the common negative differential input + Pins AIN0 to AIN2 are positive differential inputs for channels 0 to 2 + +- mode 2 : single ended and differential mixed + Pins AIN0 and AIN1 are single ended inputs for channels 0 and 1 + Pins AIN2 is the positive differential input for channel 3 + Pins AIN3 is the negative differential input for channel 3 + +- mode 3 : two differential inputs + Pins AIN0 is the positive differential input for channel 0 + Pins AIN1 is the negative differential input for channel 0 + Pins AIN2 is the positive differential input for channel 1 + Pins AIN3 is the negative differential input for channel 1 + +See the datasheet for details. + +Module parameters +----------------- + +* input_mode int + + Analog input mode: + 0 = four single ended inputs + 1 = three differential inputs + 2 = single ended and differential mixed + 3 = two differential inputs + + +Accessing PCF8591 via /sys interface +------------------------------------- + +! Be careful ! +The PCF8591 is plainly impossible to detect ! Stupid chip. +So every chip with address in the interval [48..4f] is +detected as PCF8591. If you have other chips in this address +range, the workaround is to load this module after the one +for your others chips. + +On detection (i.e. insmod, modprobe et al.), directories are being +created for each detected PCF8591: + +/sys/bus/devices/<0>-<1>/ +where <0> is the bus the chip was detected on (e. g. i2c-0) +and <1> the chip address ([48..4f]) + +Inside these directories, there are such files: +in0, in1, in2, in3, out0_enable, out0_output, name + +Name contains chip name. + +The in0, in1, in2 and in3 files are RO. Reading gives the value of the +corresponding channel. Depending on the current analog inputs configuration, +files in2 and/or in3 do not exist. Values range are from 0 to 255 for single +ended inputs and -128 to +127 for differential inputs (8-bit ADC). + +The out0_enable file is RW. Reading gives "1" for analog output enabled and +"0" for analog output disabled. Writing accepts "0" and "1" accordingly. + +The out0_output file is RW. Writing a number between 0 and 255 (8-bit DAC), send +the value to the digital-to-analog converter. Note that a voltage will +only appears on AOUT pin if aout0_enable equals 1. Reading returns the last +value written. diff --git a/Documentation/i2c/chips/sis5595 b/Documentation/i2c/chips/sis5595 new file mode 100644 index 0000000..b7ae36b --- /dev/null +++ b/Documentation/i2c/chips/sis5595 @@ -0,0 +1,106 @@ +Kernel driver sis5595 +===================== + +Supported chips: + * Silicon Integrated Systems Corp. SiS5595 Southbridge Hardware Monitor + Prefix: 'sis5595' + Addresses scanned: ISA in PCI-space encoded address + Datasheet: Publicly available at the Silicon Integrated Systems Corp. site. + +Authors: + Kyösti Mälkki , + Mark D. Studebaker , + Aurelien Jarno 2.6 port + + SiS southbridge has a LM78-like chip integrated on the same IC. + This driver is a customized copy of lm78.c + + Supports following revisions: + Version PCI ID PCI Revision + 1 1039/0008 AF or less + 2 1039/0008 B0 or greater + + Note: these chips contain a 0008 device which is incompatible with the + 5595. We recognize these by the presence of the listed + "blacklist" PCI ID and refuse to load. + + NOT SUPPORTED PCI ID BLACKLIST PCI ID + 540 0008 0540 + 550 0008 0550 + 5513 0008 5511 + 5581 0008 5597 + 5582 0008 5597 + 5597 0008 5597 + 630 0008 0630 + 645 0008 0645 + 730 0008 0730 + 735 0008 0735 + + +Module Parameters +----------------- +force_addr=0xaddr Set the I/O base address. Useful for boards + that don't set the address in the BIOS. Does not do a + PCI force; the device must still be present in lspci. + Don't use this unless the driver complains that the + base address is not set. + Example: 'modprobe sis5595 force_addr=0x290' + + +Description +----------- + +The SiS5595 southbridge has integrated hardware monitor functions. It also +has an I2C bus, but this driver only supports the hardware monitor. For the +I2C bus driver see i2c-sis5595. + +The SiS5595 implements zero or one temperature sensor, two fan speed +sensors, four or five voltage sensors, and alarms. + +On the first version of the chip, there are four voltage sensors and one +temperature sensor. + +On the second version of the chip, the temperature sensor (temp) and the +fifth voltage sensor (in4) share a pin which is configurable, but not +through the driver. Sorry. The driver senses the configuration of the pin, +which was hopefully set by the BIOS. + +Temperatures are measured in degrees Celsius. An alarm is triggered once +when the max is crossed; it is also triggered when it drops below the min +value. Measurements are guaranteed between -55 and +125 degrees, with a +resolution of 1 degree. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. An +alarm is triggered if the voltage has crossed a programmable minimum or +maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. All voltage +inputs can measure voltages between 0 and 4.08 volts, with a resolution of +0.016 volt. + +In addition to the alarms described above, there is a BTI alarm, which gets +triggered when an external chip has crossed its limits. Usually, this is +connected to some LM75-like chip; if at least one crosses its limits, this +bit gets set. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may already +have disappeared! Note that in the current implementation, all hardware +registers are read whenever any data is read (unless it is less than 1.5 +seconds since the last update). This means that you can easily miss +once-only alarms. + +The SiS5595 only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. + +Problems +-------- +Some chips refuse to be enabled. We don't know why. +The driver will recognize this and print a message in dmesg. + diff --git a/Documentation/i2c/chips/smsc47b397 b/Documentation/i2c/chips/smsc47b397 index 4737bb6..da9d80c 100644 --- a/Documentation/i2c/chips/smsc47b397 +++ b/Documentation/i2c/chips/smsc47b397 @@ -1,7 +1,19 @@ +Kernel driver smsc47b397 +======================== + +Supported chips: + * SMSC LPC47B397-NC + Prefix: 'smsc47b397' + Addresses scanned: none, address read from Super I/O config space + Datasheet: In this file + +Authors: Mark M. Hoffman + Utilitek Systems, Inc. + November 23, 2004 The following specification describes the SMSC LPC47B397-NC sensor chip -(for which there is no public datasheet available). This document was +(for which there is no public datasheet available). This document was provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected by Mark M. Hoffman . @@ -10,10 +22,10 @@ by Mark M. Hoffman . Methods for detecting the HP SIO and reading the thermal data on a dc7100. The thermal information on the dc7100 is contained in the SIO Hardware Monitor -(HWM). The information is accessed through an index/data pair. The index/data -pair is located at the HWM Base Address + 0 and the HWM Base Address + 1. The +(HWM). The information is accessed through an index/data pair. The index/data +pair is located at the HWM Base Address + 0 and the HWM Base Address + 1. The HWM Base address can be obtained from Logical Device 8, registers 0x60 (MSB) -and 0x61 (LSB). Currently we are using 0x480 for the HWM Base Address and +and 0x61 (LSB). Currently we are using 0x480 for the HWM Base Address and 0x480 and 0x481 for the index/data pair. Reading temperature information. @@ -50,7 +62,7 @@ Reading the tach LSB locks the tach MSB. The LSB Must be read first. How to convert the tach reading to RPM. -The tach reading (TCount) is given by: (Tach MSB * 256) + (Tach LSB) +The tach reading (TCount) is given by: (Tach MSB * 256) + (Tach LSB) The SIO counts the number of 90kHz (11.111us) pulses per revolution. RPM = 60/(TCount * 11.111us) diff --git a/Documentation/i2c/chips/smsc47m1 b/Documentation/i2c/chips/smsc47m1 new file mode 100644 index 0000000..34e6478 --- /dev/null +++ b/Documentation/i2c/chips/smsc47m1 @@ -0,0 +1,52 @@ +Kernel driver smsc47m1 +====================== + +Supported chips: + * SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 + Addresses scanned: none, address read from Super I/O config space + Prefix: 'smsc47m1' + Datasheets: + http://www.smsc.com/main/datasheets/47b27x.pdf + http://www.smsc.com/main/datasheets/47m10x.pdf + http://www.smsc.com/main/tools/discontinued/47m13x.pdf + http://www.smsc.com/main/datasheets/47m14x.pdf + http://www.smsc.com/main/tools/discontinued/47m15x.pdf + http://www.smsc.com/main/datasheets/47m192.pdf + +Authors: + Mark D. Studebaker , + With assistance from Bruce Allen , and his + fan.c program: http://www.lsc-group.phys.uwm.edu/%7Eballen/driver/ + Gabriele Gorla , + Jean Delvare + +Description +----------- + +The Standard Microsystems Corporation (SMSC) 47M1xx Super I/O chips +contain monitoring and PWM control circuitry for two fans. + +The 47M15x and 47M192 chips contain a full 'hardware monitoring block' +in addition to the fan monitoring and control. The hardware monitoring +block is not supported by the driver. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +PWM values are from 0 to 255. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 1.5 seconds since the last update). This means that you can easily +miss once-only alarms. + + +********************** +The lm_sensors project gratefully acknowledges the support of +Intel in the development of this driver. diff --git a/Documentation/i2c/chips/via686a b/Documentation/i2c/chips/via686a new file mode 100644 index 0000000..b82014c --- /dev/null +++ b/Documentation/i2c/chips/via686a @@ -0,0 +1,65 @@ +Kernel driver via686a +===================== + +Supported chips: + * Via VT82C686A, VT82C686B Southbridge Integrated Hardware Monitor + Prefix: 'via686a' + Addresses scanned: ISA in PCI-space encoded address + Datasheet: On request through web form (http://www.via.com.tw/en/support/datasheets/) + +Authors: + Kyösti Mälkki , + Mark D. Studebaker + Bob Dougherty + (Some conversion-factor data were contributed by + Jonathan Teh Soon Yew + and Alex van Kaam .) + +Module Parameters +----------------- + +force_addr=0xaddr Set the I/O base address. Useful for Asus A7V boards + that don't set the address in the BIOS. Does not do a + PCI force; the via686a must still be present in lspci. + Don't use this unless the driver complains that the + base address is not set. + Example: 'modprobe via686a force_addr=0x6000' + +Description +----------- + +The driver does not distinguish between the chips and reports +all as a 686A. + +The Via 686a southbridge has integrated hardware monitor functionality. +It also has an I2C bus, but this driver only supports the hardware monitor. +For the I2C bus driver, see + +The Via 686a implements three temperature sensors, two fan rotation speed +sensors, five voltage sensors and alarms. + +Temperatures are measured in degrees Celsius. An alarm is triggered once +when the Overtemperature Shutdown limit is crossed; it is triggered again +as soon as it drops below the hysteresis value. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. Voltages are internally scalled, so each voltage channel +has a different resolution and range. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 1.5 seconds since the last update). This means that you can easily +miss once-only alarms. + +The driver only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. diff --git a/Documentation/i2c/chips/w83627hf b/Documentation/i2c/chips/w83627hf new file mode 100644 index 0000000..78f37c2 --- /dev/null +++ b/Documentation/i2c/chips/w83627hf @@ -0,0 +1,66 @@ +Kernel driver w83627hf +====================== + +Supported chips: + * Winbond W83627HF (ISA accesses ONLY) + Prefix: 'w83627hf' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf + * Winbond W83627THF + Prefix: 'w83627thf' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: http://www.winbond.com/PDF/sheet/w83627thf.pdf + * Winbond W83697HF + Prefix: 'w83697hf' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: http://www.winbond.com/PDF/sheet/697hf.pdf + * Winbond W83637HF + Prefix: 'w83637hf' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: http://www.winbond.com/PDF/sheet/w83637hf.pdf + +Authors: + Frodo Looijaard , + Philip Edelbrock , + Mark Studebaker , + Bernhard C. Schrenk + +Module Parameters +----------------- + +* force_addr: int + Initialize the ISA address of the sensors +* force_i2c: int + Initialize the I2C address of the sensors +* init: int + (default is 1) + Use 'init=0' to bypass initializing the chip. + Try this if your computer crashes when you load the module. + +Description +----------- + +This driver implements support for ISA accesses *only* for +the Winbond W83627HF, W83627THF, W83697HF and W83637HF Super I/O chips. +We will refer to them collectively as Winbond chips. + +This driver supports ISA accesses, which should be more reliable +than i2c accesses. Also, for Tyan boards which contain both a +Super I/O chip and a second i2c-only Winbond chip (often a W83782D), +using this driver will avoid i2c address conflicts and complex +initialization that were required in the w83781d driver. + +If you really want i2c accesses for these Super I/O chips, +use the w83781d driver. However this is not the preferred method +now that this ISA driver has been developed. + +Technically, the w83627thf does not support a VID reading. However, it's +possible or even likely that your mainboard maker has routed these signals +to a specific set of general purpose IO pins (the Asus P4C800-E is one such +board). The w83627thf driver now interprets these as VID. If the VID on +your board doesn't work, first see doc/vid in the lm_sensors package. If +that still doesn't help, email us at lm-sensors@lm-sensors.org. + +For further information on this driver see the w83781d driver +documentation. + diff --git a/Documentation/i2c/chips/w83781d b/Documentation/i2c/chips/w83781d new file mode 100644 index 0000000..6d0e16f --- /dev/null +++ b/Documentation/i2c/chips/w83781d @@ -0,0 +1,412 @@ +Kernel driver w83781d +===================== + +Supported chips: + * Winbond W83781D + Prefix: 'w83781d' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83781d.pdf + * Winbond W83782D + Prefix: 'w83782d' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: http://www.winbond.com/PDF/sheet/w83782d.pdf + * Winbond W83783S + Prefix: 'w83783s' + Addresses scanned: I2C 0x2d + Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83783s.pdf + * Winbond W83627HF + Prefix: 'w83627hf' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf + * Winbond W83627THF + Prefix: 'w83627thf' + Addresses scanned: ISA address 0x290 (8 I/O ports) + Datasheet: http://www.winbond.com/PDF/sheet/w83627thf.pdf + * Winbond W83697HF + Prefix: 'w83697hf' + Addresses scanned: ISA 0x290 (8 I/O ports) + Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83697hf.pdf + * Asus AS99127F + Prefix: 'as99127f' + Addresses scanned: I2C 0x28 - 0x2f + Datasheet: Unavailable from Asus + +Authors: + Frodo Looijaard , + Philip Edelbrock , + Mark Studebaker + +Module parameters +----------------- + +* init int + (default 1) + Use 'init=0' to bypass initializing the chip. + Try this if your computer crashes when you load the module. + +force_subclients=bus,caddr,saddr,saddr + This is used to force the i2c addresses for subclients of + a certain chip. Typical usage is `force_subclients=0,0x2d,0x4a,0x4b' + to force the subclients of chip 0x2d on bus 0 to i2c addresses + 0x4a and 0x4b. This parameter is useful for certain Tyan boards. + +Description +----------- + +This driver implements support for the Winbond W83627HF, W83627THF, W83781D, +W83782D, W83783S, W83697HF chips, and the Asus AS99127F chips. We will refer +to them collectively as W8378* chips. + +There is quite some difference between these chips, but they are similar +enough that it was sensible to put them together in one driver. +The W83627HF chip is assumed to be identical to the ISA W83782D. +The Asus chips are similar to an I2C-only W83782D. + +Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA +as99127f 7 3 0 3 0x31 0x12c3 yes no +as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no +w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes +w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) +w83627thf 9 3 2 3 0x90 0x5ca3 no yes(LPC) +w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes +w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no +w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) + +Detection of these chips can sometimes be foiled because they can be in +an internal state that allows no clean access. If you know the address +of the chip, use a 'force' parameter; this will put them into a more +well-behaved state first. + +The W8378* implements temperature sensors (three on the W83781D and W83782D, +two on the W83783S), three fan rotation speed sensors, voltage sensors +(seven on the W83781D, nine on the W83782D and six on the W83783S), VID +lines, alarms with beep warnings, and some miscellaneous stuff. + +Temperatures are measured in degrees Celsius. There is always one main +temperature sensor, and one (W83783S) or two (W83781D and W83782D) other +sensors. An alarm is triggered for the main sensor once when the +Overtemperature Shutdown limit is crossed; it is triggered again as soon as +it drops below the Hysteresis value. A more useful behavior +can be found by setting the Hysteresis value to +127 degrees Celsius; in +this case, alarms are issued during all the time when the actual temperature +is above the Overtemperature Shutdown value. The driver sets the +hysteresis value for temp1 to 127 at initialization. + +For the other temperature sensor(s), an alarm is triggered when the +temperature gets higher then the Overtemperature Shutdown value; it stays +on until the temperature falls below the Hysteresis value. But on the +W83781D, there is only one alarm that functions for both other sensors! +Temperatures are guaranteed within a range of -55 to +125 degrees. The +main temperature sensors has a resolution of 1 degree; the other sensor(s) +of 0.5 degree. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8 for the +W83781D; 1, 2, 4, 8, 16, 32, 64 or 128 for the others) to give +the readings more range or accuracy. Not all RPM values can accurately +be represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. All voltage +inputs can measure voltages between 0 and 4.08 volts, with a resolution +of 0.016 volt. + +The VID lines encode the core voltage value: the voltage level your processor +should work with. This is hardcoded by the mainboard and/or processor itself. +It is a value in volts. When it is unconnected, you will often find the +value 3.50 V here. + +The W83782D and W83783S temperature conversion machine understands about +several kinds of temperature probes. You can program the so-called +beta value in the sensor files. '1' is the PII/Celeron diode, '2' is the +TN3904 transistor, and 3435 the default thermistor value. Other values +are (not yet) supported. + +In addition to the alarms described above, there is a CHAS alarm on the +chips which triggers if your computer case is open. + +When an alarm goes off, you can be warned by a beeping signal through +your computer speaker. It is possible to enable all beeping globally, +or only the beeping for some alarms. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 1.5 seconds since the last update). This means that you can easily +miss once-only alarms. + +The chips only update values each 1.5 seconds; reading them more often +will do no harm, but will return 'old' values. + +AS99127F PROBLEMS +----------------- +The as99127f support was developed without the benefit of a datasheet. +In most cases it is treated as a w83781d (although revision 2 of the +AS99127F looks more like a w83782d). +This support will be BETA until a datasheet is released. +One user has reported problems with fans stopping +occasionally. + +Note that the individual beep bits are inverted from the other chips. +The driver now takes care of this so that user-space applications +don't have to know about it. + +Known problems: + - Problems with diode/thermistor settings (supported?) + - One user reports fans stopping under high server load. + - Revision 2 seems to have 2 PWM registers but we don't know + how to handle them. More details below. + +These will not be fixed unless we get a datasheet. +If you have problems, please lobby Asus to release a datasheet. +Unfortunately several others have without success. +Please do not send mail to us asking for better as99127f support. +We have done the best we can without a datasheet. +Please do not send mail to the author or the sensors group asking for +a datasheet or ideas on how to convince Asus. We can't help. + + +NOTES: +----- + 783s has no in1 so that in[2-6] are compatible with the 781d/782d. + + 783s pin is programmable for -5V or temp1; defaults to -5V, + no control in driver so temp1 doesn't work. + + 782d and 783s datasheets differ on which is pwm1 and which is pwm2. + We chose to follow 782d. + + 782d and 783s pin is programmable for fan3 input or pwm2 output; + defaults to fan3 input. + If pwm2 is enabled (with echo 255 1 > pwm2), then + fan3 will report 0. + + 782d has pwm1-2 for ISA, pwm1-4 for i2c. (pwm3-4 share pins with + the ISA pins) + +Data sheet updates: +------------------ + - PWM clock registers: + + 000: master / 512 + 001: master / 1024 + 010: master / 2048 + 011: master / 4096 + 100: master / 8192 + + +Answers from Winbond tech support +--------------------------------- +> +> 1) In the W83781D data sheet section 7.2 last paragraph, it talks about +> reprogramming the R-T table if the Beta of the thermistor is not +> 3435K. The R-T table is described briefly in section 8.20. +> What formulas do I use to program a new R-T table for a given Beta? +> + We are sorry that the calculation for R-T table value is +confidential. If you have another Beta value of thermistor, we can help +to calculate the R-T table for you. But you should give us real R-T +Table which can be gotten by thermistor vendor. Therefore we will calculate +them and obtain 32-byte data, and you can fill the 32-byte data to the +register in Bank0.CR51 of W83781D. + + +> 2) In the W83782D data sheet, it mentions that pins 38, 39, and 40 are +> programmable to be either thermistor or Pentium II diode inputs. +> How do I program them for diode inputs? I can't find any register +> to program these to be diode inputs. + --> You may program Bank0 CR[5Dh] and CR[59h] registers. + + CR[5Dh] bit 1(VTIN1) bit 2(VTIN2) bit 3(VTIN3) + + thermistor 0 0 0 + diode 1 1 1 + + +(error) CR[59h] bit 4(VTIN1) bit 2(VTIN2) bit 3(VTIN3) +(right) CR[59h] bit 4(VTIN1) bit 5(VTIN2) bit 6(VTIN3) + + PII thermal diode 1 1 1 + 2N3904 diode 0 0 0 + + +Asus Clones +----------- + +We have no datasheets for the Asus clones (AS99127F and ASB100 Bach). +Here are some very useful information that were given to us by Alex Van +Kaam about how to detect these chips, and how to read their values. He +also gives advice for another Asus chipset, the Mozart-2 (which we +don't support yet). Thanks Alex! +I reworded some parts and added personal comments. + +# Detection: + +AS99127F rev.1, AS99127F rev.2 and ASB100: +- I2C address range: 0x29 - 0x2F +- If register 0x58 holds 0x31 then we have an Asus (either ASB100 or + AS99127F) +- Which one depends on register 0x4F (manufacturer ID): + 0x06 or 0x94: ASB100 + 0x12 or 0xC3: AS99127F rev.1 + 0x5C or 0xA3: AS99127F rev.2 + Note that 0x5CA3 is Winbond's ID (WEC), which let us think Asus get their + AS99127F rev.2 direct from Winbond. The other codes mean ATT and DVC, + respectively. ATT could stand for Asustek something (although it would be + very badly chosen IMHO), I don't know what DVC could stand for. Maybe + these codes simply aren't meant to be decoded that way. + +Mozart-2: +- I2C address: 0x77 +- If register 0x58 holds 0x56 or 0x10 then we have a Mozart-2 +- Of the Mozart there are 3 types: + 0x58=0x56, 0x4E=0x94, 0x4F=0x36: Asus ASM58 Mozart-2 + 0x58=0x56, 0x4E=0x94, 0x4F=0x06: Asus AS2K129R Mozart-2 + 0x58=0x10, 0x4E=0x5C, 0x4F=0xA3: Asus ??? Mozart-2 + You can handle all 3 the exact same way :) + +# Temperature sensors: + +ASB100: +- sensor 1: register 0x27 +- sensor 2 & 3 are the 2 LM75's on the SMBus +- sensor 4: register 0x17 +Remark: I noticed that on Intel boards sensor 2 is used for the CPU + and 4 is ignored/stuck, on AMD boards sensor 4 is the CPU and sensor 2 is + either ignored or a socket temperature. + +AS99127F (rev.1 and 2 alike): +- sensor 1: register 0x27 +- sensor 2 & 3 are the 2 LM75's on the SMBus +Remark: Register 0x5b is suspected to be temperature type selector. Bit 1 + would control temp1, bit 3 temp2 and bit 5 temp3. + +Mozart-2: +- sensor 1: register 0x27 +- sensor 2: register 0x13 + +# Fan sensors: + +ASB100, AS99127F (rev.1 and 2 alike): +- 3 fans, identical to the W83781D + +Mozart-2: +- 2 fans only, 1350000/RPM/div +- fan 1: register 0x28, divisor on register 0xA1 (bits 4-5) +- fan 2: register 0x29, divisor on register 0xA1 (bits 6-7) + +# Voltages: + +This is where there is a difference between AS99127F rev.1 and 2. +Remark: The difference is similar to the difference between + W83781D and W83782D. + +ASB100: +in0=r(0x20)*0.016 +in1=r(0x21)*0.016 +in2=r(0x22)*0.016 +in3=r(0x23)*0.016*1.68 +in4=r(0x24)*0.016*3.8 +in5=r(0x25)*(-0.016)*3.97 +in6=r(0x26)*(-0.016)*1.666 + +AS99127F rev.1: +in0=r(0x20)*0.016 +in1=r(0x21)*0.016 +in2=r(0x22)*0.016 +in3=r(0x23)*0.016*1.68 +in4=r(0x24)*0.016*3.8 +in5=r(0x25)*(-0.016)*3.97 +in6=r(0x26)*(-0.016)*1.503 + +AS99127F rev.2: +in0=r(0x20)*0.016 +in1=r(0x21)*0.016 +in2=r(0x22)*0.016 +in3=r(0x23)*0.016*1.68 +in4=r(0x24)*0.016*3.8 +in5=(r(0x25)*0.016-3.6)*5.14+3.6 +in6=(r(0x26)*0.016-3.6)*3.14+3.6 + +Mozart-2: +in0=r(0x20)*0.016 +in1=255 +in2=r(0x22)*0.016 +in3=r(0x23)*0.016*1.68 +in4=r(0x24)*0.016*4 +in5=255 +in6=255 + + +# PWM + +Additional info about PWM on the AS99127F (may apply to other Asus +chips as well) by Jean Delvare as of 2004-04-09: + +AS99127F revision 2 seems to have two PWM registers at 0x59 and 0x5A, +and a temperature sensor type selector at 0x5B (which basically means +that they swapped registers 0x59 and 0x5B when you compare with Winbond +chips). +Revision 1 of the chip also has the temperature sensor type selector at +0x5B, but PWM registers have no effect. + +We don't know exactly how the temperature sensor type selection works. +Looks like bits 1-0 are for temp1, bits 3-2 for temp2 and bits 5-4 for +temp3, although it is possible that only the most significant bit matters +each time. So far, values other than 0 always broke the readings. + +PWM registers seem to be split in two parts: bit 7 is a mode selector, +while the other bits seem to define a value or threshold. + +When bit 7 is clear, bits 6-0 seem to hold a threshold value. If the value +is below a given limit, the fan runs at low speed. If the value is above +the limit, the fan runs at full speed. We have no clue as to what the limit +represents. Note that there seem to be some inertia in this mode, speed +changes may need some time to trigger. Also, an hysteresis mechanism is +suspected since walking through all the values increasingly and then +decreasingly led to slightly different limits. + +When bit 7 is set, bits 3-0 seem to hold a threshold value, while bits 6-4 +would not be significant. If the value is below a given limit, the fan runs +at full speed, while if it is above the limit it runs at low speed (so this +is the contrary of the other mode, in a way). Here again, we don't know +what the limit is supposed to represent. + +One remarkable thing is that the fans would only have two or three +different speeds (transitional states left apart), not a whole range as +you usually get with PWM. + +As a conclusion, you can write 0x00 or 0x8F to the PWM registers to make +fans run at low speed, and 0x7F or 0x80 to make them run at full speed. + +Please contact us if you can figure out how it is supposed to work. As +long as we don't know more, the w83781d driver doesn't handle PWM on +AS99127F chips at all. + +Additional info about PWM on the AS99127F rev.1 by Hector Martin: + +I've been fiddling around with the (in)famous 0x59 register and +found out the following values do work as a form of coarse pwm: + +0x80 - seems to turn fans off after some time(1-2 minutes)... might be +some form of auto-fan-control based on temp? hmm (Qfan? this mobo is an +old ASUS, it isn't marketed as Qfan. Maybe some beta pre-attemp at Qfan +that was dropped at the BIOS) +0x81 - off +0x82 - slightly "on-ner" than off, but my fans do not get to move. I can +hear the high-pitched PWM sound that motors give off at too-low-pwm. +0x83 - now they do move. Estimate about 70% speed or so. +0x84-0x8f - full on + +Changing the high nibble doesn't seem to do much except the high bit +(0x80) must be set for PWM to work, else the current pwm doesn't seem to +change. + +My mobo is an ASUS A7V266-E. This behavior is similar to what I got +with speedfan under Windows, where 0-15% would be off, 15-2x% (can't +remember the exact value) would be 70% and higher would be full on. diff --git a/Documentation/i2c/chips/w83l785ts b/Documentation/i2c/chips/w83l785ts new file mode 100644 index 0000000..1841ced --- /dev/null +++ b/Documentation/i2c/chips/w83l785ts @@ -0,0 +1,39 @@ +Kernel driver w83l785ts +======================= + +Supported chips: + * Winbond W83L785TS-S + Prefix: 'w83l785ts' + Addresses scanned: I2C 0x2e + Datasheet: Publicly available at the Winbond USA website + http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf + +Authors: + Jean Delvare + +Description +----------- + +The W83L785TS-S is a digital temperature sensor. It senses the +temperature of a single external diode. The high limit is +theoretically defined as 85 or 100 degrees C through a combination +of external resistors, so the user cannot change it. Values seen so +far suggest that the two possible limits are actually 95 and 110 +degrees C. The datasheet is rather poor and obviously inaccurate +on several points including this one. + +All temperature values are given in degrees Celsius. Resolution +is 1.0 degree. See the datasheet for details. + +The w83l785ts driver will not update its values more frequently than +every other second; reading them more often will do no harm, but will +return 'old' values. + +Known Issues +------------ + +On some systems (Asus), the BIOS is known to interfere with the driver +and cause read errors. The driver will retry a given number of times +(5 by default) and then give up, returning the old value (or 0 if +there is no old value). It seems to work well enough so that you should +not notice anything. Thanks to James Bolt for helping test this feature. -- cgit v0.10.2 From 828621dda6381093ceafbe9381b6118cae3f9b13 Mon Sep 17 00:00:00 2001 From: "R.Marek@sh.cvut.cz" Date: Thu, 26 May 2005 12:42:29 +0000 Subject: [PATCH] I2C: documentation update 3/3 This patch adds information about available userspace utillities for system health monitoring drivers. Signed-off-by: Rudolf Marek Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/i2c/userspace-tools b/Documentation/i2c/userspace-tools new file mode 100644 index 0000000..2622aac --- /dev/null +++ b/Documentation/i2c/userspace-tools @@ -0,0 +1,39 @@ +Introduction +------------ + +Most mainboards have sensor chips to monitor system health (like temperatures, +voltages, fans speed). They are often connected through an I2C bus, but some +are also connected directly through the ISA bus. + +The kernel drivers make the data from the sensor chips available in the /sys +virtual filesystem. Userspace tools are then used to display or set or the +data in a more friendly manner. + +Lm-sensors +---------- + +Core set of utilites that will allow you to obtain health information, +setup monitoring limits etc. You can get them on their homepage +http://www.lm-sensors.nu/ or as a package from your Linux distribution. + +If from website: +Get lmsensors from project web site. Please note, you need only userspace +part, so compile with "make user_install" target. + +General hints to get things working: + +0) get lm-sensors userspace utils +1) compile all drivers in I2C section as modules in your kernel +2) run sensors-detect script, it will tell you what modules you need to load. +3) load them and run "sensors" command, you should see some results. +4) fix sensors.conf, labels, limits, fan divisors +5) if any more problems consult FAQ, or documentation + +Other utilites +-------------- + +If you want some graphical indicators of system health look for applications +like: gkrellm, ksensors, xsensors, wmtemp, wmsensors, wmgtemp, ksysguardd, +hardware-monitor + +If you are server administrator you can try snmpd or mrtgutils. -- cgit v0.10.2 From 5d740fe9fefda41292b5cabe70f4f8eff9f8aad0 Mon Sep 17 00:00:00 2001 From: "R.Marek@sh.cvut.cz" Date: Sat, 28 May 2005 11:26:24 +0000 Subject: [PATCH] I2C: KConfig update - some EXPERIMENTAL removal Following patch removes EXPERIMENTAL flag from some of I2C bus and chip drivers. It is removed when the driver is in kernel at least from 2.6.3 and I generally think there is no problem with it. Also this patch adds SiS 745 to help option of sis96x and it also fixes nForce2 driver entry to reflect current state. Signed-off-by: Rudolf Marek Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a0018de..916ba5e 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -7,7 +7,7 @@ menu "I2C Hardware Bus support" config I2C_ALI1535 tristate "ALI 1535" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB @@ -31,7 +31,7 @@ config I2C_ALI1563 config I2C_ALI15X3 tristate "ALI 15x3" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. @@ -41,7 +41,7 @@ config I2C_ALI15X3 config I2C_AMD756 tristate "AMD 756/766/768/8111 and nVidia nForce" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the AMD 756/766/768 mainboard I2C interfaces. The driver also includes @@ -66,7 +66,7 @@ config I2C_AMD756_S4882 config I2C_AMD8111 tristate "AMD 8111" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the second (SMBus 2.0) AMD 8111 mainboard I2C interface. @@ -109,7 +109,7 @@ config I2C_HYDRA config I2C_I801 tristate "Intel 82801 (ICH)" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following @@ -130,7 +130,7 @@ config I2C_I801 config I2C_I810 tristate "Intel 810/815" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the Intel @@ -183,7 +183,7 @@ config I2C_IOP3XX config I2C_ISA tristate "ISA Bus support" - depends on I2C && EXPERIMENTAL + depends on I2C help If you say yes to this option, support will be included for i2c interfaces that are on the ISA bus. @@ -248,12 +248,11 @@ config I2C_MPC will be called i2c-mpc. config I2C_NFORCE2 - tristate "Nvidia Nforce2" - depends on I2C && PCI && EXPERIMENTAL + tristate "Nvidia nForce2, nForce3 and nForce4" + depends on I2C && PCI help If you say yes to this option, support will be included for the Nvidia - Nforce2 family of mainboard I2C interfaces. - This driver also supports the nForce3 Pro 150 MCP. + nForce2, nForce3 and nForce4 families of mainboard I2C interfaces. This driver can also be built as a module. If so, the module will be called i2c-nforce2. @@ -305,7 +304,7 @@ config I2C_PARPORT_LIGHT config I2C_PROSAVAGE tristate "S3/VIA (Pro)Savage" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -388,7 +387,7 @@ config SCx200_ACB config I2C_SIS5595 tristate "SiS 5595" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the SiS5595 SMBus (a subset of I2C) interface. @@ -398,7 +397,7 @@ config I2C_SIS5595 config I2C_SIS630 tristate "SiS 630/730" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the SiS630 and SiS730 SMBus (a subset of I2C) interface. @@ -408,7 +407,7 @@ config I2C_SIS630 config I2C_SIS96X tristate "SiS 96x" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the SiS 96x SMBus (a subset of I2C) interfaces. Specifically, the following @@ -419,6 +418,7 @@ config I2C_SIS96X 648/961 650/961 735 + 745 This driver can also be built as a module. If so, the module will be called i2c-sis96x. @@ -449,7 +449,7 @@ config I2C_VIA config I2C_VIAPRO tristate "VIA 82C596/82C686/823x" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the VIA 82C596/82C686/823x I2C interfaces. Specifically, the following @@ -467,7 +467,7 @@ config I2C_VIAPRO config I2C_VOODOO3 tristate "Voodoo 3" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 028a6fe..2ce6907 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -11,7 +11,7 @@ config I2C_SENSOR config SENSORS_ADM1021 tristate "Analog Devices ADM1021 and compatibles" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for Analog Devices ADM1021 @@ -125,7 +125,7 @@ config SENSORS_FSCPOS config SENSORS_GL518SM tristate "Genesys Logic GL518SM" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for Genesys Logic GL518SM @@ -147,7 +147,7 @@ config SENSORS_GL520SM config SENSORS_IT87 tristate "ITE IT87xx and compatibles" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for ITE IT87xx sensor chips @@ -171,7 +171,7 @@ config SENSORS_LM63 config SENSORS_LM75 tristate "National Semiconductor LM75 and compatibles" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for National Semiconductor LM75 @@ -341,7 +341,7 @@ config SENSORS_SMSC47M1 config SENSORS_VIA686A tristate "VIA686A" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI select I2C_SENSOR select I2C_ISA help @@ -353,7 +353,7 @@ config SENSORS_VIA686A config SENSORS_W83781D tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for the Winbond W8378x series -- cgit v0.10.2 From eb071cbbc38efa4b1d707f540de2ec6283ab0894 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 4 Jun 2005 13:17:43 +0200 Subject: [PATCH] I2C: pcf8574 driver cleanup I found a possible cleanup in the pcf8574 driver. We don't need to store the read value in our private data structure, as we then never use it again. I asked Aurelien and he is fine with the change. Please apply, thanks. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 4956e9e..cfcf646 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -57,7 +57,7 @@ SENSORS_INSMOD_2(pcf8574, pcf8574a); struct pcf8574_data { struct i2c_client client; - u8 read, write; /* Register values */ + u8 write; /* Remember last written value */ }; static int pcf8574_attach_adapter(struct i2c_adapter *adapter); @@ -79,9 +79,7 @@ static struct i2c_driver pcf8574_driver = { static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); - struct pcf8574_data *data = i2c_get_clientdata(client); - data->read = i2c_smbus_read_byte(client); - return sprintf(buf, "%u\n", data->read); + return sprintf(buf, "%u\n", i2c_smbus_read_byte(client)); } static DEVICE_ATTR(read, S_IRUGO, show_read, NULL); -- cgit v0.10.2 From a0ef14837a2298a4748e2a3e8e206f086dd3b21a Mon Sep 17 00:00:00 2001 From: Grant Coady Date: Fri, 3 Jun 2005 10:05:19 +1000 Subject: [PATCH] I2C: add adm9240 driver documentation This patch adds adm9240 driver doc, with thanks to Rudolf Marek for review. Signed-off-by: Grant Coady Acked-by: Rudolf Marek Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/i2c/chips/adm9240 b/Documentation/i2c/chips/adm9240 new file mode 100644 index 0000000..35f618f --- /dev/null +++ b/Documentation/i2c/chips/adm9240 @@ -0,0 +1,177 @@ +Kernel driver adm9240 +===================== + +Supported chips: + * Analog Devices ADM9240 + Prefix: 'adm9240' + Addresses scanned: I2C 0x2c - 0x2f + Datasheet: Publicly available at the Analog Devices website + http://www.analog.com/UploadedFiles/Data_Sheets/79857778ADM9240_0.pdf + + * Dallas Semiconductor DS1780 + Prefix: 'ds1780' + Addresses scanned: I2C 0x2c - 0x2f + Datasheet: Publicly available at the Dallas Semiconductor (Maxim) website + http://pdfserv.maxim-ic.com/en/ds/DS1780.pdf + + * National Semiconductor LM81 + Prefix: 'lm81' + Addresses scanned: I2C 0x2c - 0x2f + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ds.cgi/LM/LM81.pdf + +Authors: + Frodo Looijaard , + Philip Edelbrock , + Michiel Rook , + Grant Coady with guidance + from Jean Delvare + +Interface +--------- +The I2C addresses listed above assume BIOS has not changed the +chip MSB 5-bit address. Each chip reports a unique manufacturer +identification code as well as the chip revision/stepping level. + +Description +----------- +[From ADM9240] The ADM9240 is a complete system hardware monitor for +microprocessor-based systems, providing measurement and limit comparison +of up to four power supplies and two processor core voltages, plus +temperature, two fan speeds and chassis intrusion. Measured values can +be read out via an I2C-compatible serial System Management Bus, and values +for limit comparisons can be programmed in over the same serial bus. The +high speed successive approximation ADC allows frequent sampling of all +analog channels to ensure a fast interrupt response to any out-of-limit +measurement. + +The ADM9240, DS1780 and LM81 are register compatible, the following +details are common to the three chips. Chip differences are described +after this section. + + +Measurements +------------ +The measurement cycle + +The adm9240 driver will take a measurement reading no faster than once +each two seconds. User-space may read sysfs interface faster than the +measurement update rate and will receive cached data from the most +recent measurement. + +ADM9240 has a very fast 320us temperature and voltage measurement cycle +with independent fan speed measurement cycles counting alternating rising +edges of the fan tacho inputs. + +DS1780 measurement cycle is about once per second including fan speed. + +LM81 measurement cycle is about once per 400ms including fan speed. +The LM81 12-bit extended temperature measurement mode is not supported. + +Temperature +----------- +On chip temperature is reported as degrees Celsius as 9-bit signed data +with resolution of 0.5 degrees Celsius. High and low temperature limits +are 8-bit signed data with resolution of one degree Celsius. + +Temperature alarm is asserted once the temperature exceeds the high limit, +and is cleared when the temperature falls below the temp1_max_hyst value. + +Fan Speed +--------- +Two fan tacho inputs are provided, the ADM9240 gates an internal 22.5kHz +clock via a divider to an 8-bit counter. Fan speed (rpm) is calculated by: + +rpm = (22500 * 60) / (count * divider) + +Automatic fan clock divider + + * User sets 0 to fan_min limit + - low speed alarm is disabled + - fan clock divider not changed + - auto fan clock adjuster enabled for valid fan speed reading + + * User sets fan_min limit too low + - low speed alarm is enabled + - fan clock divider set to max + - fan_min set to register value 254 which corresponds + to 664 rpm on adm9240 + - low speed alarm will be asserted if fan speed is + less than minimum measurable speed + - auto fan clock adjuster disabled + + * User sets reasonable fan speed + - low speed alarm is enabled + - fan clock divider set to suit fan_min + - auto fan clock adjuster enabled: adjusts fan_min + + * User sets unreasonably high low fan speed limit + - resolution of the low speed limit may be reduced + - alarm will be asserted + - auto fan clock adjuster enabled: adjusts fan_min + + * fan speed may be displayed as zero until the auto fan clock divider + adjuster brings fan speed clock divider back into chip measurement + range, this will occur within a few measurement cycles. + +Analog Output +------------- +An analog output provides a 0 to 1.25 volt signal intended for an external +fan speed amplifier circuit. The analog output is set to maximum value on +power up or reset. This doesn't do much on the test Intel SE440BX-2. + +Voltage Monitor + +Voltage (IN) measurement is internally scaled: + + nr label nominal maximum resolution + mV mV mV + 0 +2.5V 2500 3320 13.0 + 1 Vccp1 2700 3600 14.1 + 2 +3.3V 3300 4380 17.2 + 3 +5V 5000 6640 26.0 + 4 +12V 12000 15940 62.5 + 5 Vccp2 2700 3600 14.1 + +The reading is an unsigned 8-bit value, nominal voltage measurement is +represented by a reading of 192, being 3/4 of the measurement range. + +An alarm is asserted for any voltage going below or above the set limits. + +The driver reports and accepts voltage limits scaled to the above table. + +VID Monitor +----------- +The chip has five inputs to read the 5-bit VID and reports the mV value +based on detected CPU type. + +Chassis Intrusion +----------------- +An alarm is asserted when the CI pin goes active high. The ADM9240 +Datasheet has an example of an external temperature sensor driving +this pin. On an Intel SE440BX-2 the Chassis Intrusion header is +connected to a normally open switch. + +The ADM9240 provides an internal open drain on this line, and may output +a 20 ms active low pulse to reset an external Chassis Intrusion latch. + +Clear the CI latch by writing value 1 to the sysfs chassis_clear file. + +Alarm flags reported as 16-bit word + + bit label comment + --- ------------- -------------------------- + 0 +2.5 V_Error high or low limit exceeded + 1 VCCP_Error high or low limit exceeded + 2 +3.3 V_Error high or low limit exceeded + 3 +5 V_Error high or low limit exceeded + 4 Temp_Error temperature error + 6 FAN1_Error fan low limit exceeded + 7 FAN2_Error fan low limit exceeded + 8 +12 V_Error high or low limit exceeded + 9 VCCP2_Error high or low limit exceeded + 12 Chassis_Error CI pin went high + +Remaining bits are reserved and thus undefined. It is important to note +that alarm bits may be cleared on read, user-space may latch alarms and +provide the end-user with a method to clear alarm memory. -- cgit v0.10.2 From 30d7394b1a3df0e7cc145a543846109babd4d53b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 5 Jun 2005 21:27:28 +0200 Subject: [PATCH] I2C: lm90 uses new sysfs callbacks I updated the lm90 hardware monitoring driver to take benefit of Yani Ioannou's new sysfs callback capabilities. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c index 42795b4..ebd99df 100644 --- a/drivers/i2c/chips/lm90.c +++ b/drivers/i2c/chips/lm90.c @@ -1,7 +1,7 @@ /* * lm90.c - Part of lm_sensors, Linux kernel modules for hardware * monitoring - * Copyright (C) 2003-2004 Jean Delvare + * Copyright (C) 2003-2005 Jean Delvare * * Based on the lm83 driver. The LM90 is a sensor chip made by National * Semiconductor. It reports up to two temperatures (its own plus up to @@ -76,6 +76,7 @@ #include #include #include +#include /* * Addresses to scan @@ -205,9 +206,14 @@ struct lm90_data { int kind; /* registers values */ - s8 temp_input1, temp_low1, temp_high1; /* local */ - s16 temp_input2, temp_low2, temp_high2; /* remote, combined */ - s8 temp_crit1, temp_crit2; + s8 temp8[5]; /* 0: local input + 1: local low limit + 2: local high limit + 3: local critical limit + 4: remote critical limit */ + s16 temp11[3]; /* 0: remote input + 1: remote low limit + 2: remote high limit */ u8 temp_hyst; u8 alarms; /* bitvector */ }; @@ -216,75 +222,88 @@ struct lm90_data { * Sysfs stuff */ -#define show_temp(value, converter) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm90_data *data = lm90_update_device(dev); \ - return sprintf(buf, "%d\n", converter(data->value)); \ +static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index])); +} + +static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM90_REG_W_LOCAL_LOW, + LM90_REG_W_LOCAL_HIGH, + LM90_REG_W_LOCAL_CRIT, + LM90_REG_W_REMOTE_CRIT, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + if (data->kind == adt7461) + data->temp8[nr] = TEMP1_TO_REG_ADT7461(val); + else + data->temp8[nr] = TEMP1_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]); + up(&data->update_lock); + return count; } -show_temp(temp_input1, TEMP1_FROM_REG); -show_temp(temp_input2, TEMP2_FROM_REG); -show_temp(temp_low1, TEMP1_FROM_REG); -show_temp(temp_low2, TEMP2_FROM_REG); -show_temp(temp_high1, TEMP1_FROM_REG); -show_temp(temp_high2, TEMP2_FROM_REG); -show_temp(temp_crit1, TEMP1_FROM_REG); -show_temp(temp_crit2, TEMP1_FROM_REG); - -#define set_temp1(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm90_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - if (data->kind == adt7461) \ - data->value = TEMP1_TO_REG_ADT7461(val); \ - else \ - data->value = TEMP1_TO_REG(val); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ + +static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP2_FROM_REG(data->temp11[attr->index])); } -#define set_temp2(value, regh, regl) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm90_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - if (data->kind == adt7461) \ - data->value = TEMP2_TO_REG_ADT7461(val); \ - else \ - data->value = TEMP2_TO_REG(val); \ - i2c_smbus_write_byte_data(client, regh, data->value >> 8); \ - i2c_smbus_write_byte_data(client, regl, data->value & 0xff); \ - up(&data->update_lock); \ - return count; \ + +static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM90_REG_W_REMOTE_LOWH, + LM90_REG_W_REMOTE_LOWL, + LM90_REG_W_REMOTE_HIGHH, + LM90_REG_W_REMOTE_HIGHL, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + if (data->kind == adt7461) + data->temp11[nr] = TEMP2_TO_REG_ADT7461(val); + else + data->temp11[nr] = TEMP2_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], + data->temp11[nr] >> 8); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], + data->temp11[nr] & 0xff); + up(&data->update_lock); + return count; } -set_temp1(temp_low1, LM90_REG_W_LOCAL_LOW); -set_temp2(temp_low2, LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL); -set_temp1(temp_high1, LM90_REG_W_LOCAL_HIGH); -set_temp2(temp_high2, LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL); -set_temp1(temp_crit1, LM90_REG_W_LOCAL_CRIT); -set_temp1(temp_crit2, LM90_REG_W_REMOTE_CRIT); - -#define show_temp_hyst(value, basereg) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm90_data *data = lm90_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->basereg) \ - - TEMP1_FROM_REG(data->temp_hyst)); \ + +static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index]) + - TEMP1_FROM_REG(data->temp_hyst)); } -show_temp_hyst(temp_hyst1, temp_crit1); -show_temp_hyst(temp_hyst2, temp_crit2); -static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm90_data *data = i2c_get_clientdata(client); @@ -292,36 +311,37 @@ static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, long hyst; down(&data->update_lock); - hyst = TEMP1_FROM_REG(data->temp_crit1) - val; + hyst = TEMP1_FROM_REG(data->temp8[3]) - val; i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, HYST_TO_REG(hyst)); up(&data->update_lock); return count; } -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, + char *buf) { struct lm90_data *data = lm90_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_low1, - set_temp_low1); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, - set_temp_low2); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1, - set_temp_high1); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, - set_temp_high2); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit1, - set_temp_crit1); -static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, - set_temp_crit2); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst1, - set_temp_hyst1); -static DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_hyst2, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 1); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 1); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 2); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 2); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 3); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 4); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, + set_temphyst, 3); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* @@ -480,16 +500,26 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) lm90_init_client(new_client); /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit_hyst.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); return 0; @@ -540,16 +570,16 @@ static struct lm90_data *lm90_update_device(struct device *dev) u8 oldh, newh; dev_dbg(&client->dev, "Updating lm90 data.\n"); - data->temp_input1 = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_TEMP); - data->temp_high1 = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_HIGH); - data->temp_low1 = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_LOW); - data->temp_crit1 = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_CRIT); - data->temp_crit2 = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_CRIT); + data->temp8[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_TEMP); + data->temp8[1] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_LOW); + data->temp8[2] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_HIGH); + data->temp8[3] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_CRIT); + data->temp8[4] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_CRIT); data->temp_hyst = i2c_smbus_read_byte_data(client, LM90_REG_R_TCRIT_HYST); @@ -569,13 +599,13 @@ static struct lm90_data *lm90_update_device(struct device *dev) */ oldh = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH); - data->temp_input2 = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPL); newh = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH); if (newh != oldh) { - data->temp_input2 = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPL); #ifdef DEBUG oldh = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH); @@ -585,16 +615,16 @@ static struct lm90_data *lm90_update_device(struct device *dev) "wrong.\n"); #endif } - data->temp_input2 |= (newh << 8); + data->temp11[0] |= (newh << 8); - data->temp_high2 = (i2c_smbus_read_byte_data(client, + data->temp11[1] = (i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_LOWH) << 8) + + i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_LOWL); + data->temp11[2] = (i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_HIGHH) << 8) + i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_HIGHL); - data->temp_low2 = (i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWH) << 8) + - i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWL); data->alarms = i2c_smbus_read_byte_data(client, LM90_REG_R_STATUS); -- cgit v0.10.2 From 1a86c05121a3f56b4b928ed43f9f8ffc1376d802 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 5 Jun 2005 21:16:39 +0200 Subject: [PATCH] I2C: lm83 uses new sysfs callbacks I updated the lm83 hardware monitoring driver to take benefit of Yani Ioannou's new sysfs callback capabilities. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c index 442dc17..0e0eae4dc 100644 --- a/drivers/i2c/chips/lm83.c +++ b/drivers/i2c/chips/lm83.c @@ -1,7 +1,7 @@ /* * lm83.c - Part of lm_sensors, Linux kernel modules for hardware * monitoring - * Copyright (C) 2003 Jean Delvare + * Copyright (C) 2003-2005 Jean Delvare * * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is * a sensor chip made by National Semiconductor. It reports up to four @@ -33,6 +33,7 @@ #include #include #include +#include /* * Addresses to scan @@ -93,21 +94,20 @@ static const u8 LM83_REG_R_TEMP[] = { LM83_REG_R_LOCAL_TEMP, LM83_REG_R_REMOTE1_TEMP, LM83_REG_R_REMOTE2_TEMP, - LM83_REG_R_REMOTE3_TEMP -}; - -static const u8 LM83_REG_R_HIGH[] = { + LM83_REG_R_REMOTE3_TEMP, LM83_REG_R_LOCAL_HIGH, LM83_REG_R_REMOTE1_HIGH, LM83_REG_R_REMOTE2_HIGH, - LM83_REG_R_REMOTE3_HIGH + LM83_REG_R_REMOTE3_HIGH, + LM83_REG_R_TCRIT, }; static const u8 LM83_REG_W_HIGH[] = { LM83_REG_W_LOCAL_HIGH, LM83_REG_W_REMOTE1_HIGH, LM83_REG_W_REMOTE2_HIGH, - LM83_REG_W_REMOTE3_HIGH + LM83_REG_W_REMOTE3_HIGH, + LM83_REG_W_TCRIT, }; /* @@ -143,9 +143,9 @@ struct lm83_data { unsigned long last_updated; /* in jiffies */ /* registers values */ - s8 temp_input[4]; - s8 temp_high[4]; - s8 temp_crit; + s8 temp[9]; /* 0..3: input 1-4, + 4..7: high limit 1-4, + 8 : critical limit */ u16 alarms; /* bitvector, combined */ }; @@ -153,65 +153,55 @@ struct lm83_data { * Sysfs stuff */ -#define show_temp(suffix, value) \ -static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm83_data *data = lm83_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm83_data *data = lm83_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -show_temp(input1, temp_input[0]); -show_temp(input2, temp_input[1]); -show_temp(input3, temp_input[2]); -show_temp(input4, temp_input[3]); -show_temp(high1, temp_high[0]); -show_temp(high2, temp_high[1]); -show_temp(high3, temp_high[2]); -show_temp(high4, temp_high[3]); -show_temp(crit, temp_crit); - -#define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm83_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ + +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm83_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + data->temp[nr] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4], + data->temp[nr]); + up(&data->update_lock); + return count; } -set_temp(high1, temp_high[0], LM83_REG_W_LOCAL_HIGH); -set_temp(high2, temp_high[1], LM83_REG_W_REMOTE1_HIGH); -set_temp(high3, temp_high[2], LM83_REG_W_REMOTE2_HIGH); -set_temp(high4, temp_high[3], LM83_REG_W_REMOTE3_HIGH); -set_temp(crit, temp_crit, LM83_REG_W_TCRIT); -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, + char *buf) { struct lm83_data *data = lm83_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); -static DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input3, NULL); -static DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input4, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1, - set_temp_high1); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, - set_temp_high2); -static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_high3, - set_temp_high3); -static DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_high4, - set_temp_high4); -static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL); -static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL); -static DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp_crit, - set_temp_crit); -static DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 4); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 5); +static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 6); +static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 7); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp, + set_temp, 8); +static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* @@ -322,18 +312,30 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) */ /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp4_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp4_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); - device_create_file(&new_client->dev, &dev_attr_temp4_crit); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_crit.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); return 0; @@ -369,16 +371,11 @@ static struct lm83_data *lm83_update_device(struct device *dev) int nr; dev_dbg(&client->dev, "Updating lm83 data.\n"); - for (nr = 0; nr < 4 ; nr++) { - data->temp_input[nr] = + for (nr = 0; nr < 9; nr++) { + data->temp[nr] = i2c_smbus_read_byte_data(client, LM83_REG_R_TEMP[nr]); - data->temp_high[nr] = - i2c_smbus_read_byte_data(client, - LM83_REG_R_HIGH[nr]); } - data->temp_crit = - i2c_smbus_read_byte_data(client, LM83_REG_R_TCRIT); data->alarms = i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) -- cgit v0.10.2 From bc51ae1159c0c9a34d2400a8449e1fca3ee965b4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 5 Jun 2005 20:32:27 +0200 Subject: [PATCH] I2C: lm63 uses new sysfs callbacks I updated the lm63 hardware monitoring driver to take benefit of Yani Ioannou's new sysfs callback capabilities. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c index 18b2876..a1fd12b 100644 --- a/drivers/i2c/chips/lm63.c +++ b/drivers/i2c/chips/lm63.c @@ -1,7 +1,7 @@ /* * lm63.c - driver for the National Semiconductor LM63 temperature sensor * with integrated fan control - * Copyright (C) 2004 Jean Delvare + * Copyright (C) 2004-2005 Jean Delvare * Based on the lm90 driver. * * The LM63 is a sensor chip made by National Semiconductor. It measures @@ -43,6 +43,7 @@ #include #include #include +#include /* * Addresses to scan @@ -157,16 +158,16 @@ struct lm63_data { /* registers values */ u8 config, config_fan; - u16 fan1_input; - u16 fan1_low; + u16 fan[2]; /* 0: input + 1: low limit */ u8 pwm1_freq; u8 pwm1_value; - s8 temp1_input; - s8 temp1_high; - s16 temp2_input; - s16 temp2_high; - s16 temp2_low; - s8 temp2_crit; + s8 temp8[3]; /* 0: local input + 1: local high limit + 2: remote critical limit */ + s16 temp11[3]; /* 0: remote input + 1: remote low limit + 2: remote high limit */ u8 temp2_crit_hyst; u8 alarms; }; @@ -175,33 +176,33 @@ struct lm63_data { * Sysfs callback functions and files */ -#define show_fan(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm63_data *data = lm63_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value)); \ +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index])); } -show_fan(fan1_input); -show_fan(fan1_low); -static ssize_t set_fan1_low(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); down(&data->update_lock); - data->fan1_low = FAN_TO_REG(val); + data->fan[1] = FAN_TO_REG(val); i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB, - data->fan1_low & 0xFF); + data->fan[1] & 0xFF); i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB, - data->fan1_low >> 8); + data->fan[1] >> 8); up(&data->update_lock); return count; } -static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, + char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? @@ -209,7 +210,8 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char (2 * data->pwm1_freq)); } -static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); @@ -228,77 +230,83 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const return count; } -static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, + char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); } -#define show_temp8(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm63_data *data = lm63_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->value)); \ +static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])); } -#define show_temp11(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm63_data *data = lm63_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->value)); \ + +static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp8[1] = TEMP8_TO_REG(val); + i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); + up(&data->update_lock); + return count; } -show_temp8(temp1_input); -show_temp8(temp1_high); -show_temp11(temp2_input); -show_temp11(temp2_high); -show_temp11(temp2_low); -show_temp8(temp2_crit); - -#define set_temp8(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm63_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP8_TO_REG(val); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ + +static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])); } -#define set_temp11(value, reg_msb, reg_lsb) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm63_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP11_TO_REG(val); \ - i2c_smbus_write_byte_data(client, reg_msb, data->value >> 8); \ - i2c_smbus_write_byte_data(client, reg_lsb, data->value & 0xff); \ - up(&data->update_lock); \ - return count; \ + +static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM63_REG_REMOTE_LOW_MSB, + LM63_REG_REMOTE_LOW_LSB, + LM63_REG_REMOTE_HIGH_MSB, + LM63_REG_REMOTE_HIGH_LSB, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + data->temp11[nr] = TEMP11_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], + data->temp11[nr] >> 8); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], + data->temp11[nr] & 0xff); + up(&data->update_lock); + return count; } -set_temp8(temp1_high, LM63_REG_LOCAL_HIGH); -set_temp11(temp2_high, LM63_REG_REMOTE_HIGH_MSB, LM63_REG_REMOTE_HIGH_LSB); -set_temp11(temp2_low, LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB); /* Hysteresis register holds a relative value, while we want to present an absolute to user-space */ -static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, + char *buf) { struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp2_crit) + return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) - TEMP8_FROM_REG(data->temp2_crit_hyst)); } /* And now the other way around, user-space provides an absolute hysteresis value and we have to store a relative one */ -static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); @@ -306,36 +314,37 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute * long hyst; down(&data->update_lock); - hyst = TEMP8_FROM_REG(data->temp2_crit) - val; + hyst = TEMP8_FROM_REG(data->temp8[2]) - val; i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, HYST_TO_REG(hyst)); up(&data->update_lock); return count; } -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, + char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan1_input, NULL); -static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan1_low, - set_fan1_low); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, + set_fan, 1); static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_high, - set_temp1_high); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 1); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp2_input, NULL); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp2_low, - set_temp2_low); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp2_high, - set_temp2_high); -static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp2_crit, NULL); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 1); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 2); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2); static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, set_temp2_crit_hyst); @@ -429,17 +438,25 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) /* Register sysfs hooks */ if (data->config & 0x04) { /* tachometer enabled */ - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min.dev_attr); } device_create_file(&new_client->dev, &dev_attr_pwm1); device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); device_create_file(&new_client->dev, &dev_attr_alarms); @@ -510,14 +527,14 @@ static struct lm63_data *lm63_update_device(struct device *dev) if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { if (data->config & 0x04) { /* tachometer enabled */ /* order matters for fan1_input */ - data->fan1_input = i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_LSB) & 0xFC; - data->fan1_input |= i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_MSB) << 8; - data->fan1_low = (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_LSB) & 0xFC) - | (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_MSB) << 8); + data->fan[0] = i2c_smbus_read_byte_data(client, + LM63_REG_TACH_COUNT_LSB) & 0xFC; + data->fan[0] |= i2c_smbus_read_byte_data(client, + LM63_REG_TACH_COUNT_MSB) << 8; + data->fan[1] = (i2c_smbus_read_byte_data(client, + LM63_REG_TACH_LIMIT_LSB) & 0xFC) + | (i2c_smbus_read_byte_data(client, + LM63_REG_TACH_LIMIT_MSB) << 8); } data->pwm1_freq = i2c_smbus_read_byte_data(client, @@ -527,26 +544,26 @@ static struct lm63_data *lm63_update_device(struct device *dev) data->pwm1_value = i2c_smbus_read_byte_data(client, LM63_REG_PWM_VALUE); - data->temp1_input = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_TEMP); - data->temp1_high = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_HIGH); + data->temp8[0] = i2c_smbus_read_byte_data(client, + LM63_REG_LOCAL_TEMP); + data->temp8[1] = i2c_smbus_read_byte_data(client, + LM63_REG_LOCAL_HIGH); /* order matters for temp2_input */ - data->temp2_input = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_MSB) << 8; - data->temp2_input |= i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_LSB); - data->temp2_high = (i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_MSB) << 8) - | i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_LSB); - data->temp2_low = (i2c_smbus_read_byte_data(client, + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TEMP_MSB) << 8; + data->temp11[0] |= i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TEMP_LSB); + data->temp11[1] = (i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_LOW_MSB) << 8) | i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_LOW_LSB); - data->temp2_crit = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TCRIT); + data->temp11[2] = (i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_HIGH_MSB) << 8) + | i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_HIGH_LSB); + data->temp8[2] = i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TCRIT); data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST); -- cgit v0.10.2 From 20ad93d4e5cf5f0616198b5919ee9f304119dd4b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 5 Jun 2005 11:53:25 +0200 Subject: [PATCH] I2C: drivers/i2c/chips/it87.c: use dynamic sysfs callbacks This patch modifies the it87 hardware monitoring driver to take benefit of the new sysfs callback features introduced by Yani Ioannou, making the code much clearer and the resulting driver significantly smaller. From: Yani Ioannou Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 7984bf9..6a9b65a1 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -238,27 +239,42 @@ static struct i2c_driver it87_driver = { .detach_client = it87_detach_client, }; -static ssize_t show_in(struct device *dev, char *buf, int nr) +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); } -static ssize_t show_in_min(struct device *dev, char *buf, int nr) +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); } -static ssize_t show_in_max(struct device *dev, char *buf, int nr) +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); } -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); @@ -270,9 +286,12 @@ static ssize_t set_in_min(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); @@ -286,38 +305,14 @@ static ssize_t set_in_max(struct device *dev, const char *buf, } #define show_in_offset(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in, NULL, offset); #define limit_in_offset(offset) \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset); show_in_offset(0); limit_in_offset(0); @@ -338,24 +333,39 @@ limit_in_offset(7); show_in_offset(8); /* 3 temperatures */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); } -static ssize_t show_temp_max(struct device *dev, char *buf, int nr) +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); } -static ssize_t show_temp_min(struct device *dev, char *buf, int nr) +static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); } -static ssize_t set_temp_max(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -366,9 +376,12 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_temp_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -380,42 +393,23 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, return count; } #define show_temp_offset(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t \ -show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t \ -show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_max(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min); +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_min, set_temp_min, offset - 1); show_temp_offset(1); show_temp_offset(2); show_temp_offset(3); -static ssize_t show_sensor(struct device *dev, char *buf, int nr) +static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); u8 reg = data->sensor; /* In case the value is updated while we use it */ @@ -425,9 +419,12 @@ static ssize_t show_sensor(struct device *dev, char *buf, int nr) return sprintf(buf, "2\n"); /* thermistor */ return sprintf(buf, "0\n"); /* disabled */ } -static ssize_t set_sensor(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -450,53 +447,67 @@ static ssize_t set_sensor(struct device *dev, const char *buf, return count; } #define show_sensor_offset(offset) \ -static ssize_t show_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_sensor(dev, buf, offset - 1); \ -} \ -static ssize_t set_sensor_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_sensor(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_sensor_##offset, set_sensor_##offset); +static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ + show_sensor, set_sensor, offset - 1); show_sensor_offset(1); show_sensor_offset(2); show_sensor_offset(3); /* 3 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); } -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); } -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); } -static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0); } -static ssize_t show_pwm(struct device *dev, char *buf, int nr) +static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]); } -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -507,9 +518,12 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -547,9 +561,12 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_pwm_enable(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_pwm_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -578,9 +595,12 @@ static ssize_t set_pwm_enable(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_pwm(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -596,64 +616,23 @@ static ssize_t set_pwm(struct device *dev, const char *buf, return count; } -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_div, set_fan_##offset##_div); +#define show_fan_offset(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_div, set_fan_div, offset - 1); show_fan_offset(1); show_fan_offset(2); show_fan_offset(3); #define show_pwm_offset(offset) \ -static ssize_t show_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_enable(dev, buf, offset - 1); \ -} \ -static ssize_t show_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_enable(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_enable, \ - set_pwm##offset##_enable); \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm##offset , set_pwm##offset ); +static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ + show_pwm_enable, set_pwm_enable, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_pwm, set_pwm, offset - 1); show_pwm_offset(1); show_pwm_offset(2); @@ -861,60 +840,60 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) it87_init_client(new_client, data); /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in7_input); - device_create_file(&new_client->dev, &dev_attr_in8_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in7_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in6_max); - device_create_file(&new_client->dev, &dev_attr_in7_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp1_type); - device_create_file(&new_client->dev, &dev_attr_temp2_type); - device_create_file(&new_client->dev, &dev_attr_temp3_type); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan3_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan3_div); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); if (enable_pwm_interface) { - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); - device_create_file(&new_client->dev, &dev_attr_pwm3_enable); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm3); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); } if (data->type == it8712) { -- cgit v0.10.2 From c3bc4caedd84ad03360cb9ec04b6c44ab314588b Mon Sep 17 00:00:00 2001 From: "BGardner@Wabtec.com" Date: Fri, 3 Jun 2005 13:03:27 -0400 Subject: [PATCH] max6875: new i2c device driver This patch adds support for the MAX6875/MAX6874 chips. Signed-off-by: Ben Gardner Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/i2c/chips/max6875 b/Documentation/i2c/chips/max6875 new file mode 100644 index 0000000..b4fb49b --- /dev/null +++ b/Documentation/i2c/chips/max6875 @@ -0,0 +1,54 @@ +Kernel driver max6875 +===================== + +Supported chips: + * Maxim max6874, max6875 + Prefixes: 'max6875' + Addresses scanned: 0x50, 0x52 + Datasheets: + http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf + +Author: Ben Gardner + + +Module Parameters +----------------- + +* allow_write int + Set to non-zero to enable write permission: + *0: Read only + 1: Read and write + + +Description +----------- + +The MAXIM max6875 is a EEPROM-programmable power-supply sequencer/supervisor. +It provides timed outputs that can be used as a watchdog, if properly wired. +It also provides 512 bytes of user EEPROM. + +At reset, the max6875 reads the configuration eeprom into its configuration +registers. The chip then begins to operate according to the values in the +registers. + +See the datasheet for details on how to program the EEPROM. + + +Sysfs entries +------------- + +eeprom_user - 512 bytes of user-defined EEPROM space. Only writable if + allow_write was set and register 0x43 is 0. + +eeprom_config - 70 bytes of config EEPROM. Note that changes will not get + loaded into register space until a power cycle or device reset. + +reg_config - 70 bytes of register space. Any changes take affect immediately. + + +General Remarks +--------------- + +A typical application will require that the EEPROMs be programmed once and +never altered afterwards. + diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 2ce6907..88437d0 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -498,4 +498,16 @@ config SENSORS_M41T00 This driver can also be built as a module. If so, the module will be called m41t00. +config SENSORS_MAX6875 + tristate "MAXIM MAX6875 Power supply supervisor" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the MAX6875 + EEPROM-Programmable, Hex/Quad, Power-Suppy Sequencers/Supervisors. + + This provides a interface to program the EEPROM and reset the chip. + + This driver can also be built as a module. If so, the module + will be called max6875. + endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 5054ba5..8eed238 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o obj-$(CONFIG_SENSORS_LM90) += lm90.o obj-$(CONFIG_SENSORS_LM92) += lm92.o obj-$(CONFIG_SENSORS_MAX1619) += max1619.o +obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_M41T00) += m41t00.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c new file mode 100644 index 0000000..fe6b150 --- /dev/null +++ b/drivers/i2c/chips/max6875.c @@ -0,0 +1,473 @@ +/* + max6875.c - driver for MAX6874/MAX6875 + + Copyright (C) 2005 Ben Gardner + + Based on i2c/chips/eeprom.c + + The MAX6875 has two EEPROM sections: config and user. + At reset, the config EEPROM is read into the registers. + + This driver make 3 binary files available in sysfs: + reg_config - direct access to the registers + eeprom_config - acesses configuration eeprom space + eeprom_user - free for application use + + In our application, we put device serial & model numbers in user eeprom. + + Notes: + 1) The datasheet says that register 0x44 / EEPROM 0x8044 should NOT + be overwritten, so the driver explicitly prevents that. + 2) It's a good idea to keep the config (0x45) locked in config EEPROM. + You can temporarily enable config writes by changing register 0x45. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = {0x50, 0x52, I2C_CLIENT_END}; +static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; + +/* Insmod parameters */ +SENSORS_INSMOD_1(max6875); + +/* this param will prevent 'accidental' writes to the eeprom */ +static int allow_write = 0; +module_param(allow_write, int, 0); +MODULE_PARM_DESC(allow_write, + "Enable write access:\n" + "*0: Read only\n" + " 1: Read/Write access"); + +/* The MAX6875 can only read/write 16 bytes at a time */ +#define SLICE_SIZE 16 +#define SLICE_BITS 4 + +/* CONFIG EEPROM is at addresses 0x8000 - 0x8045, registers are at 0 - 0x45 */ +#define CONFIG_EEPROM_BASE 0x8000 +#define CONFIG_EEPROM_SIZE 0x0046 +#define CONFIG_EEPROM_SLICES 5 + +/* USER EEPROM is at addresses 0x8100 - 0x82FF */ +#define USER_EEPROM_BASE 0x8100 +#define USER_EEPROM_SIZE 0x0200 +#define USER_EEPROM_SLICES 32 + +/* MAX6875 commands */ +#define MAX6875_CMD_BLOCK_WRITE 0x83 +#define MAX6875_CMD_BLOCK_READ 0x84 +#define MAX6875_CMD_REBOOT 0x88 + +enum max6875_area_type { + max6875_register_config=0, + max6875_eeprom_config, + max6875_eeprom_user, + max6857_max +}; + +struct eeprom_block { + enum max6875_area_type type; + u8 slices; + u32 size; + u32 valid; + u32 base; + unsigned long *updated; + u8 *data; +}; + +/* Each client has this additional data */ +struct max6875_data { + struct i2c_client client; + struct semaphore update_lock; + struct eeprom_block blocks[max6857_max]; + /* the above structs point into the arrays below */ + u8 data[USER_EEPROM_SIZE + (CONFIG_EEPROM_SIZE*2)]; + unsigned long last_updated[USER_EEPROM_SLICES + (CONFIG_EEPROM_SLICES*2)]; +}; + +static int max6875_attach_adapter(struct i2c_adapter *adapter); +static int max6875_detect(struct i2c_adapter *adapter, int address, int kind); +static int max6875_detach_client(struct i2c_client *client); + +/* This is the driver that will be inserted */ +static struct i2c_driver max6875_driver = { + .owner = THIS_MODULE, + .name = "max6875", + .flags = I2C_DF_NOTIFY, + .attach_adapter = max6875_attach_adapter, + .detach_client = max6875_detach_client, +}; + +static int max6875_update_slice(struct i2c_client *client, + struct eeprom_block *blk, + int slice) +{ + struct max6875_data *data = i2c_get_clientdata(client); + int i, j, addr, count; + u8 rdbuf[SLICE_SIZE]; + int retval = 0; + + if (slice >= blk->slices) + return -1; + + down(&data->update_lock); + + if (!(blk->valid & (1 << slice)) || + (jiffies - blk->updated[slice] > 300 * HZ) || + (jiffies < blk->updated[slice])) { + dev_dbg(&client->dev, "Starting eeprom update, slice %u, base %u\n", + slice, blk->base); + + addr = blk->base + (slice << SLICE_BITS); + count = blk->size - (slice << SLICE_BITS); + if (count > SLICE_SIZE) { + count = SLICE_SIZE; + } + + /* Preset the read address */ + if (addr < 0x100) { + /* select the register */ + if (i2c_smbus_write_byte(client, addr & 0xFF)) { + dev_dbg(&client->dev, "max6875 register select has failed!\n"); + retval = -1; + goto exit; + } + } else { + /* select the eeprom */ + if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { + dev_dbg(&client->dev, "max6875 address set has failed!\n"); + retval = -1; + goto exit; + } + } + + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLOCK_READ, + rdbuf) != SLICE_SIZE) + { + retval = -1; + goto exit; + } + + memcpy(&blk->data[slice << SLICE_BITS], rdbuf, count); + } else { + for (i = 0; i < count; i++) { + j = i2c_smbus_read_byte(client); + if (j < 0) + { + retval = -1; + goto exit; + } + blk->data[(slice << SLICE_BITS) + i] = (u8) j; + } + } + blk->updated[slice] = jiffies; + blk->valid |= (1 << slice); + } + exit: + up(&data->update_lock); + return retval; +} + +static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, size_t count, + enum max6875_area_type area_type) +{ + struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); + struct max6875_data *data = i2c_get_clientdata(client); + struct eeprom_block *blk; + int slice; + + blk = &data->blocks[area_type]; + + if (off > blk->size) + return 0; + if (off + count > blk->size) + count = blk->size - off; + + /* Only refresh slices which contain requested bytes */ + for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++) + max6875_update_slice(client, blk, slice); + + memcpy(buf, &blk->data[off], count); + + return count; +} + +static ssize_t max6875_user_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_read(kobj, buf, off, count, max6875_eeprom_user); +} + +static ssize_t max6875_config_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_read(kobj, buf, off, count, max6875_eeprom_config); +} + +static ssize_t max6875_cfgreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_read(kobj, buf, off, count, max6875_register_config); +} + + +static ssize_t max6875_write(struct kobject *kobj, char *buf, loff_t off, size_t count, + enum max6875_area_type area_type) +{ + struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); + struct max6875_data *data = i2c_get_clientdata(client); + struct eeprom_block *blk; + int slice, addr, retval; + ssize_t sent = 0; + + blk = &data->blocks[area_type]; + + if (off > blk->size) + return 0; + if ((off + count) > blk->size) + count = blk->size - off; + + if (down_interruptible(&data->update_lock)) + return -EAGAIN; + + /* writing to a register is done with i2c_smbus_write_byte_data() */ + if (blk->type == max6875_register_config) { + for (sent = 0; sent < count; sent++) { + addr = off + sent; + if (addr == 0x44) + continue; + + retval = i2c_smbus_write_byte_data(client, addr, buf[sent]); + } + } else { + int cmd, val; + + /* We are writing to EEPROM */ + for (sent = 0; sent < count; sent++) { + addr = blk->base + off + sent; + cmd = addr >> 8; + val = (addr & 0xff) | (buf[sent] << 8); // reversed + + if (addr == 0x8044) + continue; + + retval = i2c_smbus_write_word_data(client, cmd, val); + + if (retval) { + goto error_exit; + } + + /* A write takes up to 11 ms */ + msleep(11); + } + } + + /* Invalidate the scratch buffer */ + for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++) + blk->valid &= ~(1 << slice); + + error_exit: + up(&data->update_lock); + + return sent; +} + +static ssize_t max6875_user_write(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_write(kobj, buf, off, count, max6875_eeprom_user); +} + +static ssize_t max6875_config_write(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_write(kobj, buf, off, count, max6875_eeprom_config); +} + +static ssize_t max6875_cfgreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_write(kobj, buf, off, count, max6875_register_config); +} + +static struct bin_attribute user_eeprom_attr = { + .attr = { + .name = "eeprom_user", + .mode = S_IRUGO | S_IWUSR | S_IWGRP, + .owner = THIS_MODULE, + }, + .size = USER_EEPROM_SIZE, + .read = max6875_user_read, + .write = max6875_user_write, +}; + +static struct bin_attribute config_eeprom_attr = { + .attr = { + .name = "eeprom_config", + .mode = S_IRUGO | S_IWUSR, + .owner = THIS_MODULE, + }, + .size = CONFIG_EEPROM_SIZE, + .read = max6875_config_read, + .write = max6875_config_write, +}; + +static struct bin_attribute config_register_attr = { + .attr = { + .name = "reg_config", + .mode = S_IRUGO | S_IWUSR, + .owner = THIS_MODULE, + }, + .size = CONFIG_EEPROM_SIZE, + .read = max6875_cfgreg_read, + .write = max6875_cfgreg_write, +}; + +static int max6875_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, max6875_detect); +} + +/* This function is called by i2c_detect */ +static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct max6875_data *data; + int err = 0; + + /* There are three ways we can read the EEPROM data: + (1) I2C block reads (faster, but unsupported by most adapters) + (2) Consecutive byte reads (100% overhead) + (3) Regular byte data reads (200% overhead) + The third method is not implemented by this driver because all + known adapters support at least the second. */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access eeprom_{read,write}_value. */ + if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct max6875_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &max6875_driver; + new_client->flags = 0; + + /* Setup the user section */ + data->blocks[max6875_eeprom_user].type = max6875_eeprom_user; + data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES; + data->blocks[max6875_eeprom_user].size = USER_EEPROM_SIZE; + data->blocks[max6875_eeprom_user].base = USER_EEPROM_BASE; + data->blocks[max6875_eeprom_user].data = data->data; + data->blocks[max6875_eeprom_user].updated = data->last_updated; + + /* Setup the config section */ + data->blocks[max6875_eeprom_config].type = max6875_eeprom_config; + data->blocks[max6875_eeprom_config].slices = CONFIG_EEPROM_SLICES; + data->blocks[max6875_eeprom_config].size = CONFIG_EEPROM_SIZE; + data->blocks[max6875_eeprom_config].base = CONFIG_EEPROM_BASE; + data->blocks[max6875_eeprom_config].data = &data->data[USER_EEPROM_SIZE]; + data->blocks[max6875_eeprom_config].updated = &data->last_updated[USER_EEPROM_SLICES]; + + /* Setup the register section */ + data->blocks[max6875_register_config].type = max6875_register_config; + data->blocks[max6875_register_config].slices = CONFIG_EEPROM_SLICES; + data->blocks[max6875_register_config].size = CONFIG_EEPROM_SIZE; + data->blocks[max6875_register_config].base = 0; + data->blocks[max6875_register_config].data = &data->data[USER_EEPROM_SIZE+CONFIG_EEPROM_SIZE]; + data->blocks[max6875_register_config].updated = &data->last_updated[USER_EEPROM_SLICES+CONFIG_EEPROM_SLICES]; + + /* Init the data */ + memset(data->data, 0xff, sizeof(data->data)); + + /* Fill in the remaining client fields */ + strlcpy(new_client->name, "max6875", I2C_NAME_SIZE); + init_MUTEX(&data->update_lock); + + /* Verify that the chip is really what we think it is */ + if ((max6875_update_slice(new_client, &data->blocks[max6875_eeprom_config], 4) < 0) || + (max6875_update_slice(new_client, &data->blocks[max6875_register_config], 4) < 0)) + goto exit_kfree; + + /* 0x41,0x42 must be zero and 0x40 must match in eeprom and registers */ + if ((data->blocks[max6875_eeprom_config].data[0x41] != 0) || + (data->blocks[max6875_eeprom_config].data[0x42] != 0) || + (data->blocks[max6875_register_config].data[0x41] != 0) || + (data->blocks[max6875_register_config].data[0x42] != 0) || + (data->blocks[max6875_eeprom_config].data[0x40] != + data->blocks[max6875_register_config].data[0x40])) + goto exit_kfree; + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_kfree; + + /* create the sysfs eeprom files with the correct permissions */ + if (allow_write == 0) { + user_eeprom_attr.attr.mode &= ~S_IWUGO; + user_eeprom_attr.write = NULL; + config_eeprom_attr.attr.mode &= ~S_IWUGO; + config_eeprom_attr.write = NULL; + config_register_attr.attr.mode &= ~S_IWUGO; + config_register_attr.write = NULL; + } + sysfs_create_bin_file(&new_client->dev.kobj, &user_eeprom_attr); + sysfs_create_bin_file(&new_client->dev.kobj, &config_eeprom_attr); + sysfs_create_bin_file(&new_client->dev.kobj, &config_register_attr); + + return 0; + +exit_kfree: + kfree(data); +exit: + return err; +} + +static int max6875_detach_client(struct i2c_client *client) +{ + int err; + + err = i2c_detach_client(client); + if (err) { + dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static int __init max6875_init(void) +{ + return i2c_add_driver(&max6875_driver); +} + +static void __exit max6875_exit(void) +{ + i2c_del_driver(&max6875_driver); +} + + +MODULE_AUTHOR("Ben Gardner "); +MODULE_DESCRIPTION("MAX6875 driver"); +MODULE_LICENSE("GPL"); + +module_init(max6875_init); +module_exit(max6875_exit); -- cgit v0.10.2 From 10c08f8100ee2c4d27b862635574cdf4ef439e67 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 6 Jun 2005 19:34:45 +0200 Subject: [PATCH] I2C: rename i2c-sysfs.h to hwmon-sysfs.h This patch renames the new linux/i2c-sysfs.h header file to linux/hwmon-sysfs.h. This names seems to be more appropriate since this file defines macros and structures not related to i2c but to hardware monitoring drivers. The patch also updates the five hardware monitoring driver which include that header file already. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c index ddbc015..3c85fe1 100644 --- a/drivers/i2c/chips/adm1026.c +++ b/drivers/i2c/chips/adm1026.c @@ -29,8 +29,8 @@ #include #include #include -#include #include +#include /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 6a9b65a1..db20c9e 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -37,8 +37,8 @@ #include #include #include -#include #include +#include #include diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c index a1fd12b..7c6f9ea 100644 --- a/drivers/i2c/chips/lm63.c +++ b/drivers/i2c/chips/lm63.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include /* * Addresses to scan diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c index 0e0eae4dc..a49008b 100644 --- a/drivers/i2c/chips/lm83.c +++ b/drivers/i2c/chips/lm83.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include /* * Addresses to scan diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c index ebd99df..a67dcad 100644 --- a/drivers/i2c/chips/lm90.c +++ b/drivers/i2c/chips/lm90.c @@ -76,7 +76,7 @@ #include #include #include -#include +#include /* * Addresses to scan diff --git a/include/linux/hwmon-sysfs.h b/include/linux/hwmon-sysfs.h new file mode 100644 index 0000000..1b5018a --- /dev/null +++ b/include/linux/hwmon-sysfs.h @@ -0,0 +1,36 @@ +/* + * hwmon-sysfs.h - hardware monitoring chip driver sysfs defines + * + * Copyright (C) 2005 Yani Ioannou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _LINUX_HWMON_SYSFS_H +#define _LINUX_HWMON_SYSFS_H + +struct sensor_device_attribute{ + struct device_attribute dev_attr; + int index; +}; +#define to_sensor_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct sensor_device_attribute, dev_attr) + +#define SENSOR_DEVICE_ATTR(_name,_mode,_show,_store,_index) \ +struct sensor_device_attribute sensor_dev_attr_##_name = { \ + .dev_attr = __ATTR(_name,_mode,_show,_store), \ + .index = _index, \ +} + +#endif /* _LINUX_HWMON_SYSFS_H */ diff --git a/include/linux/i2c-sysfs.h b/include/linux/i2c-sysfs.h deleted file mode 100644 index d7bf6ce..0000000 --- a/include/linux/i2c-sysfs.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * i2c-sysfs.h - i2c chip driver sysfs defines - * - * Copyright (C) 2005 Yani Ioannou - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef _LINUX_I2C_SYSFS_H -#define _LINUX_I2C_SYSFS_H - -struct sensor_device_attribute{ - struct device_attribute dev_attr; - int index; -}; -#define to_sensor_dev_attr(_dev_attr) \ - container_of(_dev_attr, struct sensor_device_attribute, dev_attr) - -#define SENSOR_DEVICE_ATTR(_name,_mode,_show,_store,_index) \ -struct sensor_device_attribute sensor_dev_attr_##_name = { \ - .dev_attr = __ATTR(_name,_mode,_show,_store), \ - .index = _index, \ -} - -#endif /* _LINUX_I2C_SYSFS_H */ -- cgit v0.10.2 From 69dd204b6b45987dbf9ce7058cd238d355865281 Mon Sep 17 00:00:00 2001 From: "bgardner@wabtec.com" Date: Tue, 7 Jun 2005 08:55:38 -0500 Subject: [PATCH] I2C: add new pca9539 driver This is an i2c driver for the Philips PCA9539 (16 bit I/O port). It uses the new i2c-sysfs interfaces. The patch includes documentation. It depends on the patch that renames "i2c-sysfs.h" to "hwmon-sysfs.h" Signed-off-by: Ben Gardner Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/i2c/chips/pca9539 b/Documentation/i2c/chips/pca9539 new file mode 100644 index 0000000..c4fce6a --- /dev/null +++ b/Documentation/i2c/chips/pca9539 @@ -0,0 +1,47 @@ +Kernel driver pca9539 +===================== + +Supported chips: + * Philips PCA9539 + Prefix: 'pca9539' + Addresses scanned: 0x74 - 0x77 + Datasheet: + http://www.semiconductors.philips.com/acrobat/datasheets/PCA9539_2.pdf + +Author: Ben Gardner + + +Description +----------- + +The Philips PCA9539 is a 16 bit low power I/O device. +All 16 lines can be individually configured as an input or output. +The input sense can also be inverted. +The 16 lines are split between two bytes. + + +Sysfs entries +------------- + +Each is a byte that maps to the 8 I/O bits. +A '0' suffix is for bits 0-7, while '1' is for bits 8-15. + +input[01] - read the current value +output[01] - sets the output value +direction[01] - direction of each bit: 1=input, 0=output +invert[01] - toggle the input bit sense + +input reads the actual state of the line and is always available. +The direction defaults to input for all channels. + + +General Remarks +--------------- + +Note that each output, direction, and invert entry controls 8 lines. +You should use the read, modify, write sequence. +For example. to set output bit 0 of 1. + val=$(cat output0) + val=$(( $val | 1 )) + echo $val > output0 + diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 88437d0..33de80a 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -440,6 +440,16 @@ config SENSORS_PCF8574 This driver can also be built as a module. If so, the module will be called pcf8574. +config SENSORS_PCA9539 + tristate "Philips PCA9539 16-bit I/O port" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Philips PCA9539 + 16-bit I/O port. + + This driver can also be built as a module. If so, the module + will be called pca9539. + config SENSORS_PCF8591 tristate "Philips PCF8591" depends on I2C && EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 8eed238..6bebdc1 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_SENSORS_MAX1619) += max1619.o obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_M41T00) += m41t00.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o +obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c new file mode 100644 index 0000000..9f3ad45 --- /dev/null +++ b/drivers/i2c/chips/pca9539.c @@ -0,0 +1,192 @@ +/* + pca9539.c - 16-bit I/O port with interrupt and reset + + Copyright (C) 2005 Ben Gardner + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. +*/ + +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END}; +static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; + +/* Insmod parameters */ +SENSORS_INSMOD_1(pca9539); + +enum pca9539_cmd +{ + PCA9539_INPUT_0 = 0, + PCA9539_INPUT_1 = 1, + PCA9539_OUTPUT_0 = 2, + PCA9539_OUTPUT_1 = 3, + PCA9539_INVERT_0 = 4, + PCA9539_INVERT_1 = 5, + PCA9539_DIRECTION_0 = 6, + PCA9539_DIRECTION_1 = 7, +}; + +static int pca9539_attach_adapter(struct i2c_adapter *adapter); +static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind); +static int pca9539_detach_client(struct i2c_client *client); + +/* This is the driver that will be inserted */ +static struct i2c_driver pca9539_driver = { + .owner = THIS_MODULE, + .name = "pca9539", + .flags = I2C_DF_NOTIFY, + .attach_adapter = pca9539_attach_adapter, + .detach_client = pca9539_detach_client, +}; + +struct pca9539_data { + struct i2c_client client; +}; + +/* following are the sysfs callback functions */ +static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *psa = to_sensor_dev_attr(attr); + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%d\n", i2c_smbus_read_byte_data(client, + psa->index)); +} + +static ssize_t pca9539_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *psa = to_sensor_dev_attr(attr); + struct i2c_client *client = to_i2c_client(dev); + unsigned long val = simple_strtoul(buf, NULL, 0); + if (val > 0xff) + return -EINVAL; + i2c_smbus_write_byte_data(client, psa->index, val); + return count; +} + +/* Define the device attributes */ + +#define PCA9539_ENTRY_RO(name, cmd_idx) \ + static SENSOR_DEVICE_ATTR(name, S_IRUGO, pca9539_show, NULL, cmd_idx) + +#define PCA9539_ENTRY_RW(name, cmd_idx) \ + static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9539_show, \ + pca9539_store, cmd_idx) + +PCA9539_ENTRY_RO(input0, PCA9539_INPUT_0); +PCA9539_ENTRY_RO(input1, PCA9539_INPUT_1); +PCA9539_ENTRY_RW(output0, PCA9539_OUTPUT_0); +PCA9539_ENTRY_RW(output1, PCA9539_OUTPUT_1); +PCA9539_ENTRY_RW(invert0, PCA9539_INVERT_0); +PCA9539_ENTRY_RW(invert1, PCA9539_INVERT_1); +PCA9539_ENTRY_RW(direction0, PCA9539_DIRECTION_0); +PCA9539_ENTRY_RW(direction1, PCA9539_DIRECTION_1); + +static struct attribute *pca9539_attributes[] = { + &sensor_dev_attr_input0.dev_attr.attr, + &sensor_dev_attr_input1.dev_attr.attr, + &sensor_dev_attr_output0.dev_attr.attr, + &sensor_dev_attr_output1.dev_attr.attr, + &sensor_dev_attr_invert0.dev_attr.attr, + &sensor_dev_attr_invert1.dev_attr.attr, + &sensor_dev_attr_direction0.dev_attr.attr, + &sensor_dev_attr_direction1.dev_attr.attr, + NULL +}; + +static struct attribute_group pca9539_defattr_group = { + .attrs = pca9539_attributes, +}; + +static int pca9539_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, pca9539_detect); +} + +/* This function is called by i2c_detect */ +static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct pca9539_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. */ + if (!(data = kmalloc(sizeof(struct pca9539_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct pca9539_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &pca9539_driver; + new_client->flags = 0; + + /* Detection: the pca9539 only has 8 registers (0-7). + A read of 7 should succeed, but a read of 8 should fail. */ + if ((i2c_smbus_read_byte_data(new_client, 7) < 0) || + (i2c_smbus_read_byte_data(new_client, 8) >= 0)) + goto exit_kfree; + + strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_kfree; + + /* Register sysfs hooks (don't care about failure) */ + sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group); + + return 0; + +exit_kfree: + kfree(data); +exit: + return err; +} + +static int pca9539_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int __init pca9539_init(void) +{ + return i2c_add_driver(&pca9539_driver); +} + +static void __exit pca9539_exit(void) +{ + i2c_del_driver(&pca9539_driver); +} + +MODULE_AUTHOR("Ben Gardner "); +MODULE_DESCRIPTION("PCA9539 driver"); +MODULE_LICENSE("GPL"); + +module_init(pca9539_init); +module_exit(pca9539_exit); + -- cgit v0.10.2 From c124a78d8c7475ecc43f385f34112b638c4228d9 Mon Sep 17 00:00:00 2001 From: Randy Vinson Date: Fri, 3 Jun 2005 14:36:06 -0700 Subject: [PATCH] I2C: Add support for Maxim/Dallas DS1374 Real-Time Clock Chip (1/2) Add support for Maxim/Dallas DS1374 Real-Time Clock Chip This change adds support for the Maxim/Dallas DS1374 RTC chip. This chip is an I2C-based RTC that maintains a simple 32-bit binary seconds count with battery backup support. Signed-off-by: Randy Vinson Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 33de80a..a0982da 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -417,6 +417,17 @@ config SENSORS_DS1337 This driver can also be built as a module. If so, the module will be called ds1337. +config SENSORS_DS1374 + tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Dallas Semiconductor + DS1374 real-time clock chips. + + This driver can also be built as a module. If so, the module + will be called ds1374. + config SENSORS_EEPROM tristate "EEPROM reader" depends on I2C && EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 6bebdc1..b5e6d2f 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_DS1337) += ds1337.o +obj-$(CONFIG_SENSORS_DS1374) += ds1374.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o obj-$(CONFIG_SENSORS_FSCHER) += fscher.o diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c new file mode 100644 index 0000000..1278d97 --- /dev/null +++ b/drivers/i2c/chips/ds1374.c @@ -0,0 +1,266 @@ +/* + * drivers/i2c/chips/ds1374.c + * + * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock + * + * Author: Randy Vinson + * + * Based on the m41t00.c by Mark Greer + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +/* + * This i2c client/driver wedges between the drivers/char/genrtc.c RTC + * interface and the SMBus interface of the i2c subsystem. + * It would be more efficient to use i2c msgs/i2c_transfer directly but, as + * recommened in .../Documentation/i2c/writing-clients section + * "Sending and receiving", using SMBus level communication is preferred. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DS1374_REG_TOD0 0x00 +#define DS1374_REG_TOD1 0x01 +#define DS1374_REG_TOD2 0x02 +#define DS1374_REG_TOD3 0x03 +#define DS1374_REG_WDALM0 0x04 +#define DS1374_REG_WDALM1 0x05 +#define DS1374_REG_WDALM2 0x06 +#define DS1374_REG_CR 0x07 +#define DS1374_REG_SR 0x08 +#define DS1374_REG_SR_OSF 0x80 +#define DS1374_REG_TCR 0x09 + +#define DS1374_DRV_NAME "ds1374" + +static DECLARE_MUTEX(ds1374_mutex); + +static struct i2c_driver ds1374_driver; +static struct i2c_client *save_client; + +static unsigned short ignore[] = { I2C_CLIENT_END }; +static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + .normal_i2c = normal_addr, + .normal_i2c_range = ignore, + .probe = ignore, + .probe_range = ignore, + .ignore = ignore, + .ignore_range = ignore, + .force = ignore, +}; + +static ulong ds1374_read_rtc(void) +{ + ulong time = 0; + int reg = DS1374_REG_WDALM0; + + while (reg--) { + s32 tmp; + if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) { + dev_warn(&save_client->dev, + "can't read from rtc chip\n"); + return 0; + } + time = (time << 8) | (tmp & 0xff); + } + return time; +} + +static void ds1374_write_rtc(ulong time) +{ + int reg; + + for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) { + if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff) + < 0) { + dev_warn(&save_client->dev, + "can't write to rtc chip\n"); + break; + } + time = time >> 8; + } +} + +static void ds1374_check_rtc_status(void) +{ + s32 tmp; + + tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR); + if (tmp < 0) { + dev_warn(&save_client->dev, + "can't read status from rtc chip\n"); + return; + } + if (tmp & DS1374_REG_SR_OSF) { + dev_warn(&save_client->dev, + "oscillator discontinuity flagged, time unreliable\n"); + tmp &= ~DS1374_REG_SR_OSF; + tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR, + tmp & 0xff); + if (tmp < 0) + dev_warn(&save_client->dev, + "can't clear discontinuity notification\n"); + } +} + +ulong ds1374_get_rtc_time(void) +{ + ulong t1, t2; + int limit = 10; /* arbitrary retry limit */ + + down(&ds1374_mutex); + + /* + * Since the reads are being performed one byte at a time using + * the SMBus vs a 4-byte i2c transfer, there is a chance that a + * carry will occur during the read. To detect this, 2 reads are + * performed and compared. + */ + do { + t1 = ds1374_read_rtc(); + t2 = ds1374_read_rtc(); + } while (t1 != t2 && limit--); + + up(&ds1374_mutex); + + if (t1 != t2) { + dev_warn(&save_client->dev, + "can't get consistent time from rtc chip\n"); + t1 = 0; + } + + return t1; +} + +static void ds1374_set_tlet(ulong arg) +{ + ulong t1, t2; + int limit = 10; /* arbitrary retry limit */ + + t1 = *(ulong *) arg; + + down(&ds1374_mutex); + + /* + * Since the writes are being performed one byte at a time using + * the SMBus vs a 4-byte i2c transfer, there is a chance that a + * carry will occur during the write. To detect this, the write + * value is read back and compared. + */ + do { + ds1374_write_rtc(t1); + t2 = ds1374_read_rtc(); + } while (t1 != t2 && limit--); + + up(&ds1374_mutex); + + if (t1 != t2) + dev_warn(&save_client->dev, + "can't confirm time set from rtc chip\n"); +} + +ulong new_time; + +DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time); + +int ds1374_set_rtc_time(ulong nowtime) +{ + new_time = nowtime; + + if (in_interrupt()) + tasklet_schedule(&ds1374_tasklet); + else + ds1374_set_tlet((ulong) & new_time); + + return 0; +} + +/* + ***************************************************************************** + * + * Driver Interface + * + ***************************************************************************** + */ +static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind) +{ + struct i2c_client *client; + int rc; + + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + memset(client, 0, sizeof(struct i2c_client)); + strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE); + client->flags = I2C_DF_NOTIFY; + client->addr = addr; + client->adapter = adap; + client->driver = &ds1374_driver; + + if ((rc = i2c_attach_client(client)) != 0) { + kfree(client); + return rc; + } + + save_client = client; + + ds1374_check_rtc_status(); + + return 0; +} + +static int ds1374_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, ds1374_probe); +} + +static int ds1374_detach(struct i2c_client *client) +{ + int rc; + + if ((rc = i2c_detach_client(client)) == 0) { + kfree(i2c_get_clientdata(client)); + tasklet_kill(&ds1374_tasklet); + } + return rc; +} + +static struct i2c_driver ds1374_driver = { + .owner = THIS_MODULE, + .name = DS1374_DRV_NAME, + .id = I2C_DRIVERID_DS1374, + .flags = I2C_DF_NOTIFY, + .attach_adapter = ds1374_attach, + .detach_client = ds1374_detach, +}; + +static int __init ds1374_init(void) +{ + return i2c_add_driver(&ds1374_driver); +} + +static void __exit ds1374_exit(void) +{ + i2c_del_driver(&ds1374_driver); +} + +module_init(ds1374_init); +module_exit(ds1374_exit); + +MODULE_AUTHOR("Randy Vinson "); +MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 89270ce..33f0825 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -108,6 +108,7 @@ #define I2C_DRIVERID_TDA7313 62 /* TDA7313 audio processor */ #define I2C_DRIVERID_MAX6900 63 /* MAX6900 real-time clock */ #define I2C_DRIVERID_SAA7114H 64 /* video decoder */ +#define I2C_DRIVERID_DS1374 65 /* DS1374 real time clock */ #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ -- cgit v0.10.2 From bdca3f0aedde85552099aa95ab1449bf81e4f6f5 Mon Sep 17 00:00:00 2001 From: Randy Vinson Date: Fri, 3 Jun 2005 14:43:56 -0700 Subject: [PATCH] I2C: Add support for Maxim/Dallas DS1374 Real-Time Clock Chip (2/2) This change provides support for the DS1374 Real-Time Clock chip present on the MPC8349ADS board. It depends on a previous patch which adds I2C support for the DS1374. Signed-off-by: Randy Vinson Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c index 86ca5cf..37ece15 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.c +++ b/arch/ppc/platforms/83xx/mpc834x_sys.c @@ -185,6 +185,26 @@ mpc834x_sys_init_IRQ(void) ipic_set_default_priority(); } +#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374) +extern ulong ds1374_get_rtc_time(void); +extern int ds1374_set_rtc_time(ulong); + +static int __init +mpc834x_rtc_hookup(void) +{ + struct timespec tv; + + ppc_md.get_rtc_time = ds1374_get_rtc_time; + ppc_md.set_rtc_time = ds1374_set_rtc_time; + + tv.tv_nsec = 0; + tv.tv_sec = (ppc_md.get_rtc_time)(); + do_settimeofday(&tv); + + return 0; +} +late_initcall(mpc834x_rtc_hookup); +#endif static __inline__ void mpc834x_sys_set_bat(void) { -- cgit v0.10.2 From a45cfe2cd7450e56b4f44802b34faaf2a78a6cdb Mon Sep 17 00:00:00 2001 From: Greg KH Date: Thu, 9 Jun 2005 17:39:09 +0200 Subject: [PATCH] I2C: fix up ds1374.c driver so it will build. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index 1278d97..8d20b81 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -27,7 +27,6 @@ #include #include -#include #include #define DS1374_REG_TOD0 0x00 @@ -54,11 +53,8 @@ static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, - .normal_i2c_range = ignore, .probe = ignore, - .probe_range = ignore, .ignore = ignore, - .ignore_range = ignore, .force = ignore, }; -- cgit v0.10.2 From 7c7a530463ced6011789937b24dc2bfba43c706b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 16 Jun 2005 19:24:14 +0200 Subject: [PATCH] I2C: w83781d: remove non-i2c sensor chips This patch removes the support for the W83697HF and W83627THF chips from the w83781d driver. These chips have no I2C/SMBus interface and are better supported by the Super-I/O-based w83627hf driver. Documentation was updated to reflect the support drop. Signed-off-by: Grant Coady Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/i2c/chips/w83781d b/Documentation/i2c/chips/w83781d index 6d0e16f..e545933 100644 --- a/Documentation/i2c/chips/w83781d +++ b/Documentation/i2c/chips/w83781d @@ -18,14 +18,6 @@ Supported chips: Prefix: 'w83627hf' Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf - * Winbond W83627THF - Prefix: 'w83627thf' - Addresses scanned: ISA address 0x290 (8 I/O ports) - Datasheet: http://www.winbond.com/PDF/sheet/w83627thf.pdf - * Winbond W83697HF - Prefix: 'w83697hf' - Addresses scanned: ISA 0x290 (8 I/O ports) - Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83697hf.pdf * Asus AS99127F Prefix: 'as99127f' Addresses scanned: I2C 0x28 - 0x2f @@ -53,9 +45,9 @@ force_subclients=bus,caddr,saddr,saddr Description ----------- -This driver implements support for the Winbond W83627HF, W83627THF, W83781D, -W83782D, W83783S, W83697HF chips, and the Asus AS99127F chips. We will refer -to them collectively as W8378* chips. +This driver implements support for the Winbond W83781D, W83782D, W83783S, +W83627HF chips, and the Asus AS99127F chips. We will refer to them +collectively as W8378* chips. There is quite some difference between these chips, but they are similar enough that it was sensible to put them together in one driver. @@ -67,10 +59,8 @@ as99127f 7 3 0 3 0x31 0x12c3 yes no as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) -w83627thf 9 3 2 3 0x90 0x5ca3 no yes(LPC) w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no -w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) Detection of these chips can sometimes be foiled because they can be in an internal state that allows no clean access. If you know the address diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index 4a5b06b..0bb131c 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -28,10 +28,8 @@ as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) - w83627thf 9 3 2 3 0x90 0x5ca3 no yes(LPC) w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no - w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) */ @@ -52,7 +50,7 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; /* Insmod parameters */ -SENSORS_INSMOD_6(w83781d, w83782d, w83783s, w83627hf, as99127f, w83697hf); +SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f); I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); @@ -998,13 +996,6 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) err = -EINVAL; goto ERROR0; } - if (!is_isa && kind == w83697hf) { - dev_err(&adapter->dev, - "Cannot force ISA-only chip for I2C address 0x%02x.\n", - address); - err = -EINVAL; - goto ERROR0; - } if (is_isa) if (!request_region(address, W83781D_EXTENT, @@ -1137,12 +1128,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) else if (val1 == 0x40 && vendid == winbond && !is_isa && address == 0x2d) kind = w83783s; - else if ((val1 == 0x21 || val1 == 0x90) && vendid == winbond) + else if (val1 == 0x21 && vendid == winbond) kind = w83627hf; else if (val1 == 0x31 && !is_isa && address >= 0x28) kind = as99127f; - else if (val1 == 0x60 && vendid == winbond && is_isa) - kind = w83697hf; else { if (kind == 0) dev_warn(&new_client->dev, "Ignoring 'force' " @@ -1161,14 +1150,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) } else if (kind == w83783s) { client_name = "w83783s"; } else if (kind == w83627hf) { - if (val1 == 0x90) - client_name = "w83627thf"; - else - client_name = "w83627hf"; + client_name = "w83627hf"; } else if (kind == as99127f) { client_name = "as99127f"; - } else if (kind == w83697hf) { - client_name = "w83697hf"; } /* Fill in the remaining client fields and put into the global list */ @@ -1206,7 +1190,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) /* Register sysfs hooks */ device_create_file_in(new_client, 0); - if (kind != w83783s && kind != w83697hf) + if (kind != w83783s) device_create_file_in(new_client, 1); device_create_file_in(new_client, 2); device_create_file_in(new_client, 3); @@ -1220,24 +1204,19 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file_fan(new_client, 1); device_create_file_fan(new_client, 2); - if (kind != w83697hf) - device_create_file_fan(new_client, 3); + device_create_file_fan(new_client, 3); device_create_file_temp(new_client, 1); device_create_file_temp(new_client, 2); - if (kind != w83783s && kind != w83697hf) + if (kind != w83783s) device_create_file_temp(new_client, 3); - if (kind != w83697hf) - device_create_file_vid(new_client); - - if (kind != w83697hf) - device_create_file_vrm(new_client); + device_create_file_vid(new_client); + device_create_file_vrm(new_client); device_create_file_fan_div(new_client, 1); device_create_file_fan_div(new_client, 2); - if (kind != w83697hf) - device_create_file_fan_div(new_client, 3); + device_create_file_fan_div(new_client, 3); device_create_file_alarms(new_client); @@ -1256,7 +1235,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) if (kind != as99127f && kind != w83781d) { device_create_file_sensor(new_client, 1); device_create_file_sensor(new_client, 2); - if (kind != w83783s && kind != w83697hf) + if (kind != w83783s) device_create_file_sensor(new_client, 3); } @@ -1479,7 +1458,7 @@ w83781d_init_client(struct i2c_client *client) else data->sens[i - 1] = 2; } - if ((type == w83783s || type == w83697hf) && (i == 2)) + if (type == w83783s && i == 2) break; } } @@ -1495,7 +1474,7 @@ w83781d_init_client(struct i2c_client *client) } /* Enable temp3 */ - if (type != w83783s && type != w83697hf) { + if (type != w83783s) { tmp = w83781d_read_value(client, W83781D_REG_TEMP3_CONFIG); if (tmp & 0x01) { @@ -1536,8 +1515,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) dev_dbg(dev, "Starting device update\n"); for (i = 0; i <= 8; i++) { - if ((data->type == w83783s || data->type == w83697hf) - && (i == 1)) + if (data->type == w83783s && i == 1) continue; /* 783S has no in1 */ data->in[i] = w83781d_read_value(client, W83781D_REG_IN(i)); @@ -1545,7 +1523,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) w83781d_read_value(client, W83781D_REG_IN_MIN(i)); data->in_max[i] = w83781d_read_value(client, W83781D_REG_IN_MAX(i)); - if ((data->type != w83782d) && (data->type != w83697hf) + if ((data->type != w83782d) && (data->type != w83627hf) && (i == 6)) break; } @@ -1581,7 +1559,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); data->temp_max_hyst_add[0] = w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); - if (data->type != w83783s && data->type != w83697hf) { + if (data->type != w83783s) { data->temp_add[1] = w83781d_read_value(client, W83781D_REG_TEMP(3)); data->temp_max_add[1] = @@ -1592,26 +1570,18 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) W83781D_REG_TEMP_HYST(3)); } i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); - if (data->type != w83697hf) { - data->vid = i & 0x0f; - data->vid |= - (w83781d_read_value(client, W83781D_REG_CHIPID) & - 0x01) - << 4; - } + data->vid = i & 0x0f; + data->vid |= (w83781d_read_value(client, + W83781D_REG_CHIPID) & 0x01) << 4; data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = (i >> 6) & 0x03; - if (data->type != w83697hf) { - data->fan_div[2] = (w83781d_read_value(client, - W83781D_REG_PIN) - >> 6) & 0x03; - } + data->fan_div[2] = (w83781d_read_value(client, + W83781D_REG_PIN) >> 6) & 0x03; if ((data->type != w83781d) && (data->type != as99127f)) { i = w83781d_read_value(client, W83781D_REG_VBAT); data->fan_div[0] |= (i >> 3) & 0x04; data->fan_div[1] |= (i >> 4) & 0x04; - if (data->type != w83697hf) - data->fan_div[2] |= (i >> 5) & 0x04; + data->fan_div[2] |= (i >> 5) & 0x04; } data->alarms = w83781d_read_value(client, -- cgit v0.10.2 From 0087e5ef577d0d6e664be7ab4be513b6a482e7ec Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 20 Jun 2005 14:25:45 -0700 Subject: [PATCH] I2C: fix ds1374 build Not all architectures implement asm/rtc.h Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index 8d20b81..a445736 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -27,8 +27,6 @@ #include #include -#include - #define DS1374_REG_TOD0 0x00 #define DS1374_REG_TOD1 0x01 #define DS1374_REG_TOD2 0x02 -- cgit v0.10.2 From 522c37b9d3bc2554264c2d7cbba439571a2043fb Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 22 Jun 2005 09:52:26 +0100 Subject: [PATCH] ARM: Fix sa1111.c build error caused by klist changes Signed-off-by: Russell King diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 21fce34..38c2eb6 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -721,16 +721,17 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) return ret; } +static int sa1111_remove_one(struct device *dev, void *data) +{ + device_unregister(dev); + return 0; +} + static void __sa1111_remove(struct sa1111 *sachip) { - struct list_head *l, *n; void __iomem *irqbase = sachip->base + SA1111_INTC; - list_for_each_safe(l, n, &sachip->dev->children) { - struct device *d = list_to_dev(l); - - device_unregister(d); - } + device_for_each_child(sachip->dev, NULL, sa1111_remove_one); /* disable all IRQs */ sa1111_writel(0, irqbase + SA1111_INTEN0); -- cgit v0.10.2 From ebe2a9ffa148746bae62d0f7188590a85f29f9ed Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 22 Jun 2005 09:55:04 +0100 Subject: [PATCH] ARM: Allow riscpc to parse "acorn" boot info tag Signed-off-by: Russell King diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c index 815c532..4371068 100644 --- a/arch/arm/mach-rpc/riscpc.c +++ b/arch/arm/mach-rpc/riscpc.c @@ -32,10 +32,7 @@ extern void rpc_init_irq(void); -extern unsigned int vram_size; - -#if 0 - +unsigned int vram_size; unsigned int memc_ctrl_reg; unsigned int number_mfm_drives; @@ -63,8 +60,6 @@ static int __init parse_tag_acorn(const struct tag *tag) __tagtable(ATAG_ACORN, parse_tag_acorn); -#endif - static struct map_desc rpc_io_desc[] __initdata = { { SCREEN_BASE, SCREEN_START, 2*1048576, MT_DEVICE }, /* VRAM */ { (u32)IO_BASE, IO_START, IO_SIZE , MT_DEVICE }, /* IO space */ -- cgit v0.10.2 From 052162198b89e64d37c20238412674152d614997 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 22 Jun 2005 09:56:57 +0100 Subject: [PATCH] ARM: Allow clps7500 to build without parsing "acorn" tag Signed-off-by: Russell King diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c index fdfeded..0bc7da4 100644 --- a/arch/arm/mach-clps7500/core.c +++ b/arch/arm/mach-clps7500/core.c @@ -26,6 +26,8 @@ #include #include +unsigned int vram_size; + static void cl7500_ack_irq_a(unsigned int irq) { unsigned int val, mask; -- cgit v0.10.2 From 7199acdc74dc16d2e75f83b8c65301ad19c40ef3 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Fri, 27 May 2005 22:07:23 +0200 Subject: [ALSA] Implement support for Line-in capture on SB Live 24bit. CA0106 driver Notes: MIC capture not tested yet. Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index c623858..67e56a5 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.20 + * Version: 0.0.21 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -45,6 +45,8 @@ * Added I2C and SPI registers. Filled in interrupt enable. * 0.0.20 * Added GPIO info for SB Live 24bit. + * 0.0.21 + * Implement support for Line-in capture on SB Live 24bit. * * * This code was initally based on code from ALSA's emu10k1x.c which is: @@ -475,9 +477,56 @@ /* Causes interrupts based on timer intervals. */ #define SPI 0x7a /* SPI: Serial Interface Register */ #define I2C_A 0x7b /* I2C Address. 32 bit */ -#define I2C_0 0x7c /* I2C Data Port 0. 32 bit */ -#define I2C_1 0x7d /* I2C Data Port 1. 32 bit */ - +#define I2C_D0 0x7c /* I2C Data Port 0. 32 bit */ +#define I2C_D1 0x7d /* I2C Data Port 1. 32 bit */ +//I2C values +#define I2C_A_ADC_ADD_MASK 0x000000fe //The address is a 7 bit address +#define I2C_A_ADC_RW_MASK 0x00000001 //bit mask for R/W +#define I2C_A_ADC_TRANS_MASK 0x00000010 //Bit mask for I2c address DAC value +#define I2C_A_ADC_ABORT_MASK 0x00000020 //Bit mask for I2C transaction abort flag +#define I2C_A_ADC_LAST_MASK 0x00000040 //Bit mask for Last word transaction +#define I2C_A_ADC_BYTE_MASK 0x00000080 //Bit mask for Byte Mode + +#define I2C_A_ADC_ADD 0x00000034 //This is the Device address for ADC +#define I2C_A_ADC_READ 0x00000001 //To perform a read operation +#define I2C_A_ADC_START 0x00000100 //Start I2C transaction +#define I2C_A_ADC_ABORT 0x00000200 //I2C transaction abort +#define I2C_A_ADC_LAST 0x00000400 //I2C last transaction +#define I2C_A_ADC_BYTE 0x00000800 //I2C one byte mode + +#define I2C_D_ADC_REG_MASK 0xfe000000 //ADC address register +#define I2C_D_ADC_DAT_MASK 0x01ff0000 //ADC data register + +#define ADC_TIMEOUT 0x00000007 //ADC Timeout Clock Disable +#define ADC_IFC_CTRL 0x0000000b //ADC Interface Control +#define ADC_MASTER 0x0000000c //ADC Master Mode Control +#define ADC_POWER 0x0000000d //ADC PowerDown Control +#define ADC_ATTEN_ADCL 0x0000000e //ADC Attenuation ADCL +#define ADC_ATTEN_ADCR 0x0000000f //ADC Attenuation ADCR +#define ADC_ALC_CTRL1 0x00000010 //ADC ALC Control 1 +#define ADC_ALC_CTRL2 0x00000011 //ADC ALC Control 2 +#define ADC_ALC_CTRL3 0x00000012 //ADC ALC Control 3 +#define ADC_NOISE_CTRL 0x00000013 //ADC Noise Gate Control +#define ADC_LIMIT_CTRL 0x00000014 //ADC Limiter Control +#define ADC_MUX 0x00000015 //ADC Mux offset + +#if 0 +/* FIXME: Not tested yet. */ +#define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain +#define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB +#define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute +#define ADC_MUTE 0x000000c0 //Value to mute ADC +#define ADC_OSR 0x00000008 //Mask for ADC oversample rate select +#define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock +#define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter +#define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window +#endif + +#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux +#define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux +#define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux +#define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used) +#define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux #define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ #define PCM_FRONT_CHANNEL 0 @@ -513,6 +562,7 @@ typedef struct { char * name; int ac97; int gpio_type; + int i2c_adc; } ca0106_details_t; // definition of the chip-specific record @@ -555,3 +605,6 @@ void snd_ca0106_ptr_write(ca0106_t *emu, unsigned int chn, unsigned int data); +int snd_ca0106_i2c_write(ca0106_t *emu, u32 reg, u32 value); + + diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index a56e68e..58d9026 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.22 + * Version: 0.0.23 * * FEATURES currently supported: * Front, Rear and Center/LFE. @@ -77,6 +77,8 @@ * Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.) * 0.0.22 * Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 + * 0.0.23 + * Implement support for Line-in capture on SB Live 24bit. * * BUGS: * Some stability problems when unloading the snd-ca0106 kernel module. @@ -173,15 +175,18 @@ static ca0106_details_t ca0106_chip_details[] = { /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ { .serial = 0x10061102, .name = "Live! 7.1 24bit [SB0410]", - .gpio_type = 1 } , + .gpio_type = 1, + .i2c_adc = 1 } , /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ { .serial = 0x10071102, .name = "Live! 7.1 24bit [SB0413]", - .gpio_type = 1 } , + .gpio_type = 1, + .i2c_adc = 1 } , /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ { .serial = 0x10091462, .name = "MSI K8N Diamond MB [SB0438]", - .gpio_type = 1 } , + .gpio_type = 1, + .i2c_adc = 1 } , { .serial = 0, .name = "AudigyLS [Unknown]" } }; @@ -257,6 +262,59 @@ void snd_ca0106_ptr_write(ca0106_t *emu, spin_unlock_irqrestore(&emu->emu_lock, flags); } +int snd_ca0106_i2c_write(ca0106_t *emu, + u32 reg, + u32 value) +{ + u32 tmp; + int timeout=0; + int status; + int retry; + if ((reg > 0x7f) || (value > 0x1ff)) + { + snd_printk("i2c_write: invalid values.\n"); + return -EINVAL; + } + + tmp = reg << 25 | value << 16; + snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); + snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp); + + for(retry=0;retry<10;retry++) + { + /* Send the data to i2c */ + tmp = snd_ca0106_ptr_read(emu, I2C_A, 0); + tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); + tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); + snd_ca0106_ptr_write(emu, I2C_A, 0, tmp); + + /* Wait till the transaction ends */ + while(1) + { + status = snd_ca0106_ptr_read(emu, I2C_A, 0); + //snd_printk("I2C:status=0x%x\n", status); + timeout++; + if((status & I2C_A_ADC_START)==0) + break; + + if(timeout>1000) + break; + } + //Read back and see if the transaction is successful + if((status & I2C_A_ADC_ABORT)==0) + break; + } + + if(retry==10) + { + snd_printk("Writing to ADC failed!\n"); + return -EINVAL; + } + + return 0; +} + + static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) { unsigned long flags; @@ -1177,6 +1235,10 @@ static int __devinit snd_ca0106_create(snd_card_t *card, //outl(0x00000009, chip->port+HCFG); outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ + if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ + snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ + } + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_ca0106_free(chip); diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 3e5161a..1c9cc82 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.17 + * Version: 0.0.18 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -39,7 +39,9 @@ * Modified Copyright message. * 0.0.17 * Add iec958 file in proc file system to show status of SPDIF in. - * + * 0.0.18 + * Implement support for Line-in capture on SB Live 24bit. + * * This code was initally based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes * @@ -407,6 +409,20 @@ static void snd_ca0106_proc_reg_write(snd_info_entry_t *entry, } } +static void snd_ca0106_proc_i2c_write(snd_info_entry_t *entry, + snd_info_buffer_t * buffer) +{ + ca0106_t *emu = entry->private_data; + char line[64]; + unsigned int reg, val; + while (!snd_info_get_line(buffer, line, sizeof(line))) { + if (sscanf(line, "%x %x", ®, &val) != 2) + continue; + if ((reg <= 0x7f) || (val <= 0x1ff)) { + snd_ca0106_i2c_write(emu, reg, val); + } + } +} int __devinit snd_ca0106_proc_init(ca0106_t * emu) { @@ -431,6 +447,13 @@ int __devinit snd_ca0106_proc_init(ca0106_t * emu) entry->mode |= S_IWUSR; // entry->private_data = emu; } + if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { + snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_i2c_write); + entry->c.text.write_size = 64; + entry->c.text.write = snd_ca0106_proc_i2c_write; + entry->mode |= S_IWUSR; +// entry->private_data = emu; + } if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read2); return 0; -- cgit v0.10.2 From ed144f3cdcf8f9b9280e04ca1a831c85a8fbb488 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Fri, 27 May 2005 23:28:27 +0200 Subject: [ALSA] Add Mic capture support. CA0106 driver Notes: This adds a new mixer item to switch between Mic and Line-in. Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 67e56a5..beac9da 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -589,6 +589,7 @@ struct snd_ca0106 { u32 spdif_bits[4]; /* s/pdif out setup */ int spdif_enable; int capture_source; + int capture_mic_line_in; struct snd_dma_buffer buffer; }; diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 48e2486..0e5e9ce 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.16 + * Version: 0.0.17 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -37,6 +37,8 @@ * Separated ca0106.c into separate functional .c files. * 0.0.16 * Modified Copyright message. + * 0.0.17 + * Implement Mic and Line in Capture. * * This code was initally based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes @@ -183,6 +185,65 @@ static snd_kcontrol_new_t snd_ca0106_capture_source __devinitdata = .put = snd_ca0106_capture_source_put }; +static int snd_ca0106_capture_mic_line_in_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[2] = { "Line in", "Mic in" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_ca0106_capture_mic_line_in_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ca0106_t *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in; + return 0; +} + +static int snd_ca0106_capture_mic_line_in_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ca0106_t *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + u32 tmp; + + val = ucontrol->value.enumerated.item[0] ; + change = (emu->capture_mic_line_in != val); + if (change) { + emu->capture_mic_line_in = val; + if (val) { + snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */ + tmp = inl(emu->port+GPIO) & ~0x400; + tmp = tmp | 0x400; + outl(tmp, emu->port+GPIO); + snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); + } else { + snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */ + tmp = inl(emu->port+GPIO) & ~0x400; + outl(tmp, emu->port+GPIO); + snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); + } + } + return change; +} + +static snd_kcontrol_new_t snd_ca0106_capture_mic_line_in __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic/Line in Capture", + .info = snd_ca0106_capture_mic_line_in_info, + .get = snd_ca0106_capture_mic_line_in_get, + .put = snd_ca0106_capture_mic_line_in_put +}; + static int snd_ca0106_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; @@ -620,6 +681,12 @@ int __devinit snd_ca0106_mixer(ca0106_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; + if (emu->details->i2c_adc == 1) { + if ((kctl = snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(card, kctl))) + return err; + } if ((kctl = snd_ctl_new1(&snd_ca0106_spdif_control, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) -- cgit v0.10.2 From 883130b476e7f8baa608dabe52c455ac351f7c39 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 28 May 2005 13:28:21 +0200 Subject: [ALSA] Implement S32_LE(24bit) and 96000 capture rates etc. CA0106 driver Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 58d9026..1c26206 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -216,10 +216,10 @@ static snd_pcm_hardware_t snd_ca0106_capture_hw = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, + .rate_min = 44100, + .rate_max = 192000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = ((65536 - 64) * 8), @@ -607,6 +607,61 @@ static int snd_ca0106_pcm_prepare_capture(snd_pcm_substream_t *substream) snd_pcm_runtime_t *runtime = substream->runtime; ca0106_pcm_t *epcm = runtime->private_data; int channel = epcm->channel_id; + u32 hcfg_mask = HCFG_CAPTURE_S32_LE; + u32 hcfg_set = 0x00000000; + u32 hcfg; + u32 over_sampling=0x2; + u32 reg71_mask = 0x0000c000 ; /* Global. Set ADC rate. */ + u32 reg71_set = 0; + u32 reg71; + + //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); + //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base); + //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes); + /* reg71 controls ADC rate. */ + switch (runtime->rate) { + case 44100: + reg71_set = 0x00004000; + break; + case 48000: + reg71_set = 0; + break; + case 96000: + reg71_set = 0x00008000; + over_sampling=0xa; + break; + case 192000: + reg71_set = 0x0000c000; + over_sampling=0xa; + break; + default: + reg71_set = 0; + break; + } + /* Format is a global setting */ + /* FIXME: Only let the first channel accessed set this. */ + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + hcfg_set = 0; + break; + case SNDRV_PCM_FORMAT_S32_LE: + hcfg_set = HCFG_CAPTURE_S32_LE; + break; + default: + hcfg_set = 0; + break; + } + hcfg = inl(emu->port + HCFG) ; + hcfg = (hcfg & ~hcfg_mask) | hcfg_set; + outl(hcfg, emu->port + HCFG); + reg71 = snd_ca0106_ptr_read(emu, 0x71, 0); + reg71 = (reg71 & ~reg71_mask) | reg71_set; + snd_ca0106_ptr_write(emu, 0x71, 0, reg71); + if (emu->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ + snd_ca0106_i2c_write(emu, ADC_MASTER, over_sampling); /* Adjust the over sampler to better suit the capture rate. */ + } + + //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); snd_ca0106_ptr_write(emu, 0x13, channel, 0); snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); -- cgit v0.10.2 From 8fabab15dc64d4aaed0e9dddf3482c128a0347a2 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 28 May 2005 16:35:49 +0200 Subject: [ALSA] Be more specific with which I2C channel to use. CA0106 driver Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 1c26206..bfd558c 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -277,7 +277,10 @@ int snd_ca0106_i2c_write(ca0106_t *emu, } tmp = reg << 25 | value << 16; - snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); + /* Not sure what this I2C channel controls. */ + /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */ + + /* This controls the I2C connected to the WM8775 ADC Codec */ snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp); for(retry=0;retry<10;retry++) -- cgit v0.10.2 From 87d61c290b5de63cc18ed5ec8103e30fe297373e Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Sun, 29 May 2005 15:08:23 +0200 Subject: [ALSA] MC97 modem mixer in sound/pci/ac97 AC97 Codec Simple MC97 modem mixer with two common controls: Off-hook and CID, and Si3056 MC specific control: Modem Speaker. Signed-off-by: Sasha Khapyorsky Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 36a33ae..996fcfb 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -150,7 +150,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, { 0x4e534350, 0xffffffff, "LM4550", NULL, NULL }, { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, -{ 0x53494c20, 0xffffffe0, "Si3036,8", NULL, mpatch_si3036 }, +{ 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, { 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99] @@ -666,6 +666,11 @@ AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1) static const snd_kcontrol_new_t snd_ac97_control_eapd = AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1); +static const snd_kcontrol_new_t snd_ac97_controls_modem_switches[2] = { +AC97_SINGLE("Off-hook Switch", AC97_GPIO_STATUS, 0, 1, 0), +AC97_SINGLE("Caller ID Switch", AC97_GPIO_STATUS, 2, 1, 0) +}; + /* change the existing EAPD control as inverted */ static void set_inv_eapd(ac97_t *ac97, snd_kcontrol_t *kctl) { @@ -1526,13 +1531,25 @@ static int snd_ac97_mixer_build(ac97_t * ac97) static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97) { - /* TODO */ + int err, idx; + //printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG)); snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH)); snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH)); snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff); snd_ac97_write(ac97, AC97_GPIO_WAKEUP, 0x0); snd_ac97_write(ac97, AC97_MISC_AFE, 0x0); + + /* build modem switches */ + for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++) + if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_modem_switches[idx], ac97))) < 0) + return err; + + /* build chip specific controls */ + if (ac97->build_ops->build_specific) + if ((err = ac97->build_ops->build_specific(ac97)) < 0) + return err; + return 0; } diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index b8106413..a15eb85 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2459,12 +2459,29 @@ int patch_it2646(ac97_t * ac97) return 0; } -/* Si3036/8 specific registers */ +/* + * Si3036 codec + */ + #define AC97_SI3036_CHIP_ID 0x5a +#define AC97_SI3036_LINE_CFG 0x5c + +static const snd_kcontrol_new_t snd_ac97_controls_si3036[] = { +AC97_DOUBLE("Modem Speaker Volume", 0x5c, 14, 12, 3, 1) +}; + +static int patch_si3036_specific(ac97_t * ac97) +{ + return patch_build_controls(ac97, snd_ac97_controls_si3036, ARRAY_SIZE(snd_ac97_controls_si3036)); +} + +static struct snd_ac97_build_ops patch_si3036_ops = { + .build_specific = patch_si3036_specific, +}; int mpatch_si3036(ac97_t * ac97) { - //printk("mpatch_si3036: chip id = %x\n", snd_ac97_read(ac97, 0x5a)); + ac97->build_ops = &patch_si3036_ops; snd_ac97_write_cache(ac97, 0x5c, 0xf210 ); snd_ac97_write_cache(ac97, 0x68, 0); return 0; -- cgit v0.10.2 From 83a5b72ad7c7cbd0d155d922733b2429f46801bf Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Sun, 29 May 2005 15:10:07 +0200 Subject: [ALSA] PCI modem drivers update ATIIXP-modem driver,Intel8x0-modem driver,VIA82xx-modem driver Modem drivers (atiixp-modem, intel8x0m, via82xx-modem) migration for using MC97 generic modem mixer for off-hook operation. Signed-off-by: Sasha Khapyorsky Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 9220aae..a6b4b8d 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -463,6 +463,11 @@ static unsigned short snd_atiixp_ac97_read(ac97_t *ac97, unsigned short reg) static void snd_atiixp_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { atiixp_t *chip = ac97->private_data; + if (reg == AC97_GPIO_STATUS) { + atiixp_write(chip, MODEM_OUT_GPIO, + (val << ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT) | ATI_REG_MODEM_OUT_GPIO_EN); + return; + } snd_atiixp_codec_write(chip, ac97->num, reg, val); } @@ -663,44 +668,33 @@ static int snd_atiixp_pcm_trigger(snd_pcm_substream_t *substream, int cmd) { atiixp_t *chip = snd_pcm_substream_chip(substream); atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data; - unsigned int reg = 0; - int i; + int err = 0; snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL); - if (cmd != SNDRV_PCM_TRIGGER_START && cmd != SNDRV_PCM_TRIGGER_STOP) - return -EINVAL; - spin_lock(&chip->reg_lock); - - /* hook off/on: via GPIO_OUT */ - for (i = 0; i < NUM_ATI_CODECS; i++) { - if (chip->ac97[i]) { - reg = snd_ac97_read(chip->ac97[i], AC97_GPIO_STATUS); - break; - } - } - if(cmd == SNDRV_PCM_TRIGGER_START) - reg |= AC97_GPIO_LINE1_OH; - else - reg &= ~AC97_GPIO_LINE1_OH; - reg = (reg << ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT) | ATI_REG_MODEM_OUT_GPIO_EN ; - atiixp_write(chip, MODEM_OUT_GPIO, reg); - - if (cmd == SNDRV_PCM_TRIGGER_START) { + switch(cmd) { + case SNDRV_PCM_TRIGGER_START: dma->ops->enable_transfer(chip, 1); dma->running = 1; - } else { + break; + case SNDRV_PCM_TRIGGER_STOP: dma->ops->enable_transfer(chip, 0); dma->running = 0; + break; + default: + err = -EINVAL; + break; } + if (! err) { snd_atiixp_check_bus_busy(chip); if (cmd == SNDRV_PCM_TRIGGER_STOP) { dma->ops->flush_dma(chip); snd_atiixp_check_bus_busy(chip); } + } spin_unlock(&chip->reg_lock); - return 0; + return err; } diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index f655cf9..bb758c7 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -35,7 +35,6 @@ #include #include #include -#include #include MODULE_AUTHOR("Jaroslav Kysela "); @@ -292,60 +291,9 @@ static struct pci_device_id snd_intel8x0m_ids[] = { #endif { 0, } }; -static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol, - snd_ctl_elem_value_t *ucontrol); -static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol, - snd_ctl_elem_value_t *ucontrol); -static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol, - snd_ctl_elem_info_t *uinfo); - -#define PRIVATE_VALUE_INITIALIZER(r,m) (((r) & 0xffff) << 16 | ((m) & 0xffff)) -#define PRIVATE_VALUE_MASK(control) ((control)->private_value & 0xffff) -#define PRIVATE_VALUE_REG(control) (((control)->private_value >> 16) & 0xffff) - -static snd_kcontrol_new_t snd_intel8x0m_mixer_switches[] __devinitdata = { - { .name = "Off-hook Switch", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = snd_intel8x0m_switch_default_info, - .get = snd_intel8x0m_switch_default_get, - .put = snd_intel8x0m_switch_default_put, - .private_value = PRIVATE_VALUE_INITIALIZER(AC97_GPIO_STATUS,AC97_GPIO_LINE1_OH) - } -}; MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids); -static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol, - snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol, - snd_ctl_elem_value_t *ucontrol) -{ - unsigned short mask = PRIVATE_VALUE_MASK(kcontrol); - unsigned short reg = PRIVATE_VALUE_REG(kcontrol); - intel8x0_t *chip = snd_kcontrol_chip(kcontrol); - unsigned int status; - status = snd_ac97_read(chip->ac97, reg) & mask ? 1 : 0; - ucontrol->value.integer.value[0] = status; - return 0; -} -static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol, - snd_ctl_elem_value_t *ucontrol) -{ - unsigned short mask = PRIVATE_VALUE_MASK(kcontrol); - unsigned short reg = PRIVATE_VALUE_REG(kcontrol); - intel8x0_t *chip = snd_kcontrol_chip(kcontrol); - unsigned short new_status = ucontrol->value.integer.value[0] ? mask : ~mask; - return snd_ac97_update_bits(chip->ac97, reg, - mask, new_status); -} /* * Lowlevel I/O - busmaster */ @@ -700,21 +648,6 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substrea return bytes_to_frames(substream->runtime, ptr); } -static int snd_intel8x0m_pcm_trigger(snd_pcm_substream_t *substream, int cmd) -{ - /* hook off/on on start/stop */ - /* Moved this to mixer control */ - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - break; - case SNDRV_PCM_TRIGGER_STOP: - break; - default: - return -EINVAL; - } - return snd_intel8x0_pcm_trigger(substream,cmd); -} - static int snd_intel8x0m_pcm_prepare(snd_pcm_substream_t * substream) { intel8x0_t *chip = snd_pcm_substream_chip(substream); @@ -810,7 +743,7 @@ static snd_pcm_ops_t snd_intel8x0m_playback_ops = { .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0m_pcm_prepare, - .trigger = snd_intel8x0m_pcm_trigger, + .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer, }; @@ -821,7 +754,7 @@ static snd_pcm_ops_t snd_intel8x0m_capture_ops = { .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0m_pcm_prepare, - .trigger = snd_intel8x0m_pcm_trigger, + .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer, }; @@ -949,7 +882,6 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) ac97_t *x97; int err; unsigned int glob_sta = 0; - unsigned int idx; static ac97_bus_ops_t ops = { .write = snd_intel8x0_codec_write, .read = snd_intel8x0_codec_read, @@ -985,10 +917,6 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) chip->ichd[ICHD_MDMIN].ac97 = x97; chip->ichd[ICHD_MDMOUT].ac97 = x97; } - for (idx = 0; idx < ARRAY_SIZE(snd_intel8x0m_mixer_switches); idx++) { - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_intel8x0m_mixer_switches[idx], chip))) < 0) - goto __err; - } chip->in_ac97_init = 0; return 0; diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 276ce52..e10fceb 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -420,7 +420,10 @@ static void snd_via82xx_codec_write(ac97_t *ac97, { via82xx_t *chip = ac97->private_data; unsigned int xval; - + if(reg == AC97_GPIO_STATUS) { + outl(val, VIAREG(chip, GPI_STATUS)); + return; + } xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY; xval <<= VIA_REG_AC97_CODEC_ID_SHIFT; xval |= reg << VIA_REG_AC97_CMD_SHIFT; @@ -544,25 +547,6 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd) return 0; } -static int snd_via82xx_modem_pcm_trigger(snd_pcm_substream_t * substream, int cmd) -{ - via82xx_t *chip = snd_pcm_substream_chip(substream); - unsigned int val = 0; - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - val = snd_ac97_read(chip->ac97, AC97_GPIO_STATUS); - outl(val|AC97_GPIO_LINE1_OH, VIAREG(chip, GPI_STATUS)); - break; - case SNDRV_PCM_TRIGGER_STOP: - val = snd_ac97_read(chip->ac97, AC97_GPIO_STATUS); - outl(val&~AC97_GPIO_LINE1_OH, VIAREG(chip, GPI_STATUS)); - break; - default: - break; - } - return snd_via82xx_pcm_trigger(substream, cmd); -} - /* * pointer callbacks */ @@ -806,7 +790,7 @@ static snd_pcm_ops_t snd_via686_playback_ops = { .hw_params = snd_via82xx_hw_params, .hw_free = snd_via82xx_hw_free, .prepare = snd_via82xx_pcm_prepare, - .trigger = snd_via82xx_modem_pcm_trigger, + .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via686_pcm_pointer, .page = snd_pcm_sgbuf_ops_page, }; @@ -819,7 +803,7 @@ static snd_pcm_ops_t snd_via686_capture_ops = { .hw_params = snd_via82xx_hw_params, .hw_free = snd_via82xx_hw_free, .prepare = snd_via82xx_pcm_prepare, - .trigger = snd_via82xx_modem_pcm_trigger, + .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via686_pcm_pointer, .page = snd_pcm_sgbuf_ops_page, }; -- cgit v0.10.2 From 299676b1d792ca643f37ff4f3275694a841739b7 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 29 May 2005 15:21:02 +0200 Subject: [ALSA] sound/pci/ca0106: Use the DMA_32BIT_MASK constant CA0106 driver Use the DMA_32BIT_MASK constant from dma-mapping.h when calling pci_set_dma_mask() or pci_set_consistent_dma_mask() See http://marc.theaimsgroup.com/?t=108001993000001&r=1&w=2 for details Signed-off-by: Tobias Klauser Signed-off-by: Domen Puncer Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index bfd558c..85caf1b 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -138,6 +138,7 @@ #include #include #include +#include #include #include #include @@ -1132,8 +1133,8 @@ static int __devinit snd_ca0106_create(snd_card_t *card, if ((err = pci_enable_device(pci)) < 0) return err; - if (pci_set_dma_mask(pci, 0xffffffffUL) < 0 || - pci_set_consistent_dma_mask(pci, 0xffffffffUL) < 0) { + if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { printk(KERN_ERR "error to set 32bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; -- cgit v0.10.2 From 5cbff89cbc1087870c32ecb0b7f1965f93ec5401 Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Mon, 30 May 2005 08:09:56 +0200 Subject: [ALSA] Modem support for ALI5451 ALI5451 driver This patch adds modem support for ali5451. Since it is same pci device all is done in ali5451.c. Signed-off-by: Sasha Khapyorsky Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 038f56a..eb5c36d 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -98,6 +98,8 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); #define ALI_LEF_CHANNEL 23 #define ALI_SURR_LEFT_CHANNEL 26 #define ALI_SURR_RIGHT_CHANNEL 25 +#define ALI_MODEM_IN_CHANNEL 21 +#define ALI_MODEM_OUT_CHANNEL 20 #define SNDRV_ALI_VOICE_TYPE_PCM 01 #define SNDRV_ALI_VOICE_TYPE_OTH 02 @@ -122,7 +124,15 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); #define ALI_SCTRL 0x48 #define ALI_SPDIF_OUT_ENABLE 0x20 +#define ALI_SCTRL_LINE_IN2 (1 << 9) +#define ALI_SCTRL_GPIO_IN2 (1 << 13) +#define ALI_SCTRL_LINE_OUT_EN (1 << 20) +#define ALI_SCTRL_GPIO_OUT_EN (1 << 23) +#define ALI_SCTRL_CODEC1_READY (1 << 24) +#define ALI_SCTRL_CODEC2_READY (1 << 25) #define ALI_AC97_GPIO 0x4c +#define ALI_AC97_GPIO_ENABLE 0x8000 +#define ALI_AC97_GPIO_DATA_SHIFT 16 #define ALI_SPDIF_CS 0x70 #define ALI_SPDIF_CTRL 0x74 #define ALI_SPDIF_IN_FUNC_ENABLE 0x02 @@ -143,6 +153,7 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); #define TARGET_REACHED 0x00008000 #define MIXER_OVERFLOW 0x00000800 #define MIXER_UNDERFLOW 0x00000400 + #define GPIO_IRQ 0x01000000 #define ALI_SBBL_SBCL 0xc0 #define ALI_SBCTRL_SBE2R_SBDD 0xc4 #define ALI_STIMER 0xc8 @@ -162,6 +173,9 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); #define ALI_REG(codec, x) ((codec)->port + x) +#define MAX_CODECS 2 + + typedef struct snd_stru_ali ali_t; typedef struct snd_ali_stru_voice snd_ali_voice_t; @@ -245,7 +259,7 @@ struct snd_stru_ali { struct pci_dev *pci_m7101; snd_card_t *card; - snd_pcm_t *pcm; + snd_pcm_t *pcm[MAX_CODECS]; alidev_t synth; snd_ali_channel_control_t chregs; @@ -255,8 +269,10 @@ struct snd_stru_ali { unsigned int spurious_irq_count; unsigned int spurious_irq_max_delta; + unsigned int num_of_codecs; + ac97_bus_t *ac97_bus; - ac97_t *ac97; + ac97_t *ac97[MAX_CODECS]; unsigned short ac97_ext_id; unsigned short ac97_ext_status; @@ -489,7 +505,12 @@ static void snd_ali_codec_write(ac97_t *ac97, ali_t *codec = ac97->private_data; snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val); - snd_ali_codec_poke(codec, 0, reg, val); + if(reg == AC97_GPIO_STATUS) { + outl((val << ALI_AC97_GPIO_DATA_SHIFT)|ALI_AC97_GPIO_ENABLE, + ALI_REG(codec, ALI_AC97_GPIO)); + return; + } + snd_ali_codec_poke(codec, ac97->num, reg, val); return ; } @@ -499,7 +520,7 @@ static unsigned short snd_ali_codec_read(ac97_t *ac97, unsigned short reg) ali_t *codec = ac97->private_data; snd_ali_printk("codec_read reg=%xh.\n", reg); - return (snd_ali_codec_peek(codec, 0, reg)); + return (snd_ali_codec_peek(codec, ac97->num, reg)); } /* @@ -1051,7 +1072,7 @@ static irqreturn_t snd_ali_card_interrupt(int irq, } -static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec) +static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec, int channel) { snd_ali_voice_t *pvoice = NULL; unsigned long flags; @@ -1061,7 +1082,8 @@ static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec) spin_lock_irqsave(&codec->voice_alloc, flags); if (type == SNDRV_ALI_VOICE_TYPE_PCM) { - idx = snd_ali_find_free_channel(codec,rec); + idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) : + snd_ali_find_free_channel(codec,rec); if(idx < 0) { snd_printk("ali_alloc_voice: err.\n"); spin_unlock_irqrestore(&codec->voice_alloc, flags); @@ -1297,7 +1319,7 @@ static int snd_ali_playback_hw_params(snd_pcm_substream_t * substream, if (params_buffer_size(hw_params)/2 != params_period_size(hw_params)) { if (evoice == NULL) { - evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0); + evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0, -1); if (evoice == NULL) return -ENOMEM; pvoice->extra = evoice; @@ -1328,13 +1350,13 @@ static int snd_ali_playback_hw_free(snd_pcm_substream_t * substream) return 0; } -static int snd_ali_capture_hw_params(snd_pcm_substream_t * substream, +static int snd_ali_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) { return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } -static int snd_ali_capture_hw_free(snd_pcm_substream_t * substream) +static int snd_ali_hw_free(snd_pcm_substream_t * substream) { return snd_pcm_lib_free_pages(substream); } @@ -1428,7 +1450,7 @@ static int snd_ali_playback_prepare(snd_pcm_substream_t * substream) } -static int snd_ali_capture_prepare(snd_pcm_substream_t * substream) +static int snd_ali_prepare(snd_pcm_substream_t * substream) { ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1446,11 +1468,13 @@ static int snd_ali_capture_prepare(snd_pcm_substream_t * substream) spin_lock_irqsave(&codec->reg_lock, flags); - snd_ali_printk("capture_prepare...\n"); + snd_ali_printk("ali_prepare...\n"); snd_ali_enable_special_channel(codec,pvoice->number); - Delta = snd_ali_convert_rate(runtime->rate, 1); + Delta = (pvoice->number == ALI_MODEM_IN_CHANNEL || + pvoice->number == ALI_MODEM_OUT_CHANNEL) ? + 0x1000 : snd_ali_convert_rate(runtime->rate, pvoice->mode); // Prepare capture intr channel if (pvoice->number == ALI_SPDIF_IN_CHANNEL) { @@ -1534,7 +1558,7 @@ static snd_pcm_uframes_t snd_ali_playback_pointer(snd_pcm_substream_t *substream } -static snd_pcm_uframes_t snd_ali_capture_pointer(snd_pcm_substream_t *substream) +static snd_pcm_uframes_t snd_ali_pointer(snd_pcm_substream_t *substream) { ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1616,7 +1640,8 @@ static void snd_ali_pcm_free_substream(snd_pcm_runtime_t *runtime) } } -static int snd_ali_playback_open(snd_pcm_substream_t * substream) +static int snd_ali_open(snd_pcm_substream_t * substream, int rec, int channel, + snd_pcm_hardware_t *phw) { ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1624,7 +1649,7 @@ static int snd_ali_playback_open(snd_pcm_substream_t * substream) unsigned long flags = 0; spin_lock_irqsave(&codec->reg_lock, flags); - pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0); + pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, rec, channel); if (pvoice == NULL) { spin_unlock_irqrestore(&codec->reg_lock, flags); return -EAGAIN; @@ -1636,49 +1661,31 @@ static int snd_ali_playback_open(snd_pcm_substream_t * substream) runtime->private_data = pvoice; runtime->private_free = snd_ali_pcm_free_substream; - runtime->hw = snd_ali_playback; + runtime->hw = *phw; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024); return 0; } +static int snd_ali_playback_open(snd_pcm_substream_t * substream) +{ + return snd_ali_open(substream, 0, -1, &snd_ali_playback); +} static int snd_ali_capture_open(snd_pcm_substream_t * substream) { - ali_t *codec = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_ali_voice_t *pvoice; - unsigned long flags; - - spin_lock_irqsave(&codec->reg_lock, flags); - pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 1); - if (pvoice == NULL) { - spin_unlock_irqrestore(&codec->reg_lock, flags); - return -EAGAIN; - } - pvoice->codec = codec; - spin_unlock_irqrestore(&codec->reg_lock, flags); - - pvoice->substream = substream; - runtime->private_data = pvoice; - runtime->private_free = snd_ali_pcm_free_substream; - runtime->hw = snd_ali_capture; - snd_pcm_set_sync(substream); - snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024); - return 0; + return snd_ali_open(substream, 1, -1, &snd_ali_capture); } - static int snd_ali_playback_close(snd_pcm_substream_t * substream) { return 0; } -static int snd_ali_capture_close(snd_pcm_substream_t * substream) +static int snd_ali_close(snd_pcm_substream_t * substream) { ali_t *codec = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data; + snd_ali_voice_t *pvoice = (snd_ali_voice_t *) substream->runtime->private_data; snd_ali_disable_special_channel(codec,pvoice->number); @@ -1698,29 +1705,121 @@ static snd_pcm_ops_t snd_ali_playback_ops = { static snd_pcm_ops_t snd_ali_capture_ops = { .open = snd_ali_capture_open, - .close = snd_ali_capture_close, + .close = snd_ali_close, .ioctl = snd_ali_ioctl, - .hw_params = snd_ali_capture_hw_params, - .hw_free = snd_ali_capture_hw_free, - .prepare = snd_ali_capture_prepare, + .hw_params = snd_ali_hw_params, + .hw_free = snd_ali_hw_free, + .prepare = snd_ali_prepare, + .trigger = snd_ali_trigger, + .pointer = snd_ali_pointer, +}; + +/* + * Modem PCM + */ + +static int snd_ali_modem_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + ali_t *chip = snd_pcm_substream_chip(substream); + unsigned int modem_num = chip->num_of_codecs - 1; + snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_RATE, params_rate(hw_params)); + snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_LEVEL, 0); + return snd_ali_hw_params(substream, hw_params); +} + +static snd_pcm_hardware_t snd_ali_modem = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_KNOT|SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000, + .rate_min = 8000, + .rate_max = 16000, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = (256*1024), + .period_bytes_min = 64, + .period_bytes_max = (256*1024), + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + +static int snd_ali_modem_open(snd_pcm_substream_t * substream, int rec, int channel) +{ + static unsigned int rates [] = {8000,9600,12000,16000}; + static snd_pcm_hw_constraint_list_t hw_constraint_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, + }; + int err = snd_ali_open(substream, rec, channel, &snd_ali_modem); + if (err) + return err; + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates); +} + +static int snd_ali_modem_playback_open(snd_pcm_substream_t * substream) +{ + return snd_ali_modem_open(substream, 0, ALI_MODEM_OUT_CHANNEL); +} + +static int snd_ali_modem_capture_open(snd_pcm_substream_t * substream) +{ + return snd_ali_modem_open(substream, 1, ALI_MODEM_IN_CHANNEL); +} + +static snd_pcm_ops_t snd_ali_modem_playback_ops = { + .open = snd_ali_modem_playback_open, + .close = snd_ali_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_ali_modem_hw_params, + .hw_free = snd_ali_hw_free, + .prepare = snd_ali_prepare, + .trigger = snd_ali_trigger, + .pointer = snd_ali_pointer, +}; + +static snd_pcm_ops_t snd_ali_modem_capture_ops = { + .open = snd_ali_modem_capture_open, + .close = snd_ali_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_ali_modem_hw_params, + .hw_free = snd_ali_hw_free, + .prepare = snd_ali_prepare, .trigger = snd_ali_trigger, - .pointer = snd_ali_capture_pointer, + .pointer = snd_ali_pointer, +}; + + +struct ali_pcm_description { + char *name; + unsigned int playback_num; + unsigned int capture_num; + snd_pcm_ops_t *playback_ops; + snd_pcm_ops_t *capture_ops; }; static void snd_ali_pcm_free(snd_pcm_t *pcm) { ali_t *codec = pcm->private_data; - codec->pcm = NULL; + codec->pcm[pcm->device] = NULL; } -static int __devinit snd_ali_pcm(ali_t * codec, int device, snd_pcm_t ** rpcm) + +static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_description *desc) { snd_pcm_t *pcm; int err; - if (rpcm) *rpcm = NULL; - err = snd_pcm_new(codec->card, "ALI 5451", device, ALI_CHANNELS, 1, &pcm); + err = snd_pcm_new(codec->card, desc->name, device, + desc->playback_num, desc->capture_num, &pcm); if (err < 0) { snd_printk("snd_ali_pcm: err called snd_pcm_new.\n"); return err; @@ -1728,20 +1827,36 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, snd_pcm_t ** rpcm) pcm->private_data = codec; pcm->private_free = snd_ali_pcm_free; pcm->info_flags = 0; - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ali_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ali_capture_ops); + if (desc->playback_ops) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, desc->playback_ops); + if (desc->capture_ops) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, desc->capture_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(codec->pci), 64*1024, 128*1024); pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; - strcpy(pcm->name, "ALI 5451"); - codec->pcm = pcm; - if (rpcm) *rpcm = pcm; + strcpy(pcm->name, desc->name); + codec->pcm[0] = pcm; return 0; } +struct ali_pcm_description ali_pcms[] = { + { "ALI 5451", ALI_CHANNELS, 1, &snd_ali_playback_ops, &snd_ali_capture_ops }, + { "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops } +}; + +static int __devinit snd_ali_build_pcms(ali_t *codec) +{ + int i, err; + for(i = 0 ; i < codec->num_of_codecs && i < ARRAY_SIZE(ali_pcms) ; i++) + if((err = snd_ali_pcm(codec, i, &ali_pcms[i])) < 0) + return err; + return 0; +} + + #define ALI5451_SPDIF(xname, xindex, value) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ .info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \ @@ -1860,14 +1975,14 @@ static void snd_ali_mixer_free_ac97_bus(ac97_bus_t *bus) static void snd_ali_mixer_free_ac97(ac97_t *ac97) { ali_t *codec = ac97->private_data; - codec->ac97 = NULL; + codec->ac97[ac97->num] = NULL; } static int __devinit snd_ali_mixer(ali_t * codec) { ac97_template_t ac97; unsigned int idx; - int err; + int i, err; static ac97_bus_ops_t ops = { .write = snd_ali_codec_write, .read = snd_ali_codec_read, @@ -1880,10 +1995,16 @@ static int __devinit snd_ali_mixer(ali_t * codec) memset(&ac97, 0, sizeof(ac97)); ac97.private_data = codec; ac97.private_free = snd_ali_mixer_free_ac97; - if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97)) < 0) { - snd_printk("ali mixer creating error.\n"); + + for ( i = 0 ; i < codec->num_of_codecs ; i++) { + ac97.num = i; + if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i])) < 0) { + snd_printk("ali mixer %d creating error.\n", i); + if(i == 0) return err; } + } + if (codec->spdif_support) { for(idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); idx++) { err=snd_ctl_add(codec->card, snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec)); @@ -1904,8 +2025,12 @@ static int ali_suspend(snd_card_t *card, pm_message_t state) if (! im) return 0; - snd_pcm_suspend_all(chip->pcm); - snd_ac97_suspend(chip->ac97); + for(i = 0 ; i < chip->num_of_codecs ; i++) { + if (chip->pcm[i]) + snd_pcm_suspend_all(chip->pcm[i]); + if(chip->ac97[i]) + snd_ac97_suspend(chip->ac97[i]); + } spin_lock_irq(&chip->reg_lock); @@ -1969,7 +2094,9 @@ static int ali_resume(snd_card_t *card) spin_unlock_irq(&chip->reg_lock); - snd_ac97_resume(chip->ac97); + for(i = 0 ; i < chip->num_of_codecs ; i++) + if(chip->ac97[i]) + snd_ac97_resume(chip->ac97[i]); return 0; } @@ -2036,11 +2163,37 @@ static int snd_ali_chip_init(ali_t *codec) codec->spdif_mask = 0x00000002; } + codec->num_of_codecs = 1; + + /* secondary codec - modem */ + if (inl(ALI_REG(codec, ALI_SCTRL)) & ALI_SCTRL_CODEC2_READY) { + codec->num_of_codecs++; + outl(inl(ALI_REG(codec, ALI_SCTRL)) | + (ALI_SCTRL_LINE_IN2|ALI_SCTRL_GPIO_IN2|ALI_SCTRL_LINE_OUT_EN), + ALI_REG(codec, ALI_SCTRL)); + } + snd_ali_printk("chip initialize succeed.\n"); return 0; } +/* proc for register dump */ +static void snd_ali_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buf) +{ + ali_t *codec = entry->private_data; + int i; + for(i = 0 ; i < 256 ; i+= 4) + snd_iprintf(buf, "%02x: %08x\n", i, inl(ALI_REG(codec, i))); +} + +static void __devinit snd_ali_proc_init(ali_t *codec) +{ + snd_info_entry_t *entry; + if(!snd_card_proc_new(codec->card, "ali5451", &entry)) + snd_info_set_text_ops(entry, codec, 1024, snd_ali_proc_read); +} + static int __devinit snd_ali_resources(ali_t *codec) { int err; @@ -2233,11 +2386,13 @@ static int __devinit snd_ali_probe(struct pci_dev *pci, } snd_ali_printk("pcm building ...\n"); - if ((err = snd_ali_pcm(codec, 0, NULL)) < 0) { + if ((err = snd_ali_build_pcms(codec)) < 0) { snd_card_free(card); return err; } + snd_ali_proc_init(codec); + strcpy(card->driver, "ALI5451"); strcpy(card->shortname, "ALI 5451"); -- cgit v0.10.2 From 745cac56ba6b0222d97a4bf0e347149f20518bf1 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 30 May 2005 11:49:05 +0200 Subject: [ALSA] via82xx - added 0x1071/0x8399 to while list VIA82xx driver - 0x1071, 0x8399 == VIA_DXS_ENABLE - Umax AB 595T (VIA K8N800A - VT8237) - reporter: Honza Machacek Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index bb322de..4c47fc8 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2161,6 +2161,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ { .vendor = 0x1043, .device = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ + { .vendor = 0x1071, .device = 0x8399, .action = VIA_DXS_ENABLE }, /* Umax AB 595T (VIA K8N800A - VT8237) */ { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ { .vendor = 0x1106, .device = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ -- cgit v0.10.2 From 69ad07cf98d0ef65cac67bac2ea4381bb499bea8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 30 May 2005 14:48:16 +0200 Subject: [ALSA] AC97 - renamed vendor/device to subvendor/subdevice where appropriate AC97 Codec,ATIIXP driver,VIA82xx driver To avoid confusion, the structure members vendor/device were renamed to subvendor/subdevice, because we compare them with PCI subsystem vendor and subsystem device. Signed-off-by: Jaroslav Kysela diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 996eeab..1309c12 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -573,8 +573,8 @@ enum { }; struct ac97_quirk { - unsigned short vendor; /* PCI vendor id */ - unsigned short device; /* PCI device id */ + unsigned short subvendor; /* PCI subsystem vendor id */ + unsigned short subdevice; /* PCI sybsystem device id */ unsigned short mask; /* device id bit mask, 0 = accept all */ unsigned int codec_id; /* codec id (if any), 0 = accept all */ const char *name; /* name shown as info */ diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 996fcfb..a4b72cd 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -2542,11 +2542,11 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o return result; } - for (; quirk->vendor; quirk++) { - if (quirk->vendor != ac97->subsystem_vendor) + for (; quirk->subvendor; quirk++) { + if (quirk->subvendor != ac97->subsystem_vendor) continue; - if ((! quirk->mask && quirk->device == ac97->subsystem_device) || - quirk->device == (quirk->mask & ac97->subsystem_device)) { + if ((! quirk->mask && quirk->subdevice == ac97->subsystem_device) || + quirk->subdevice == (quirk->mask & ac97->subsystem_device)) { if (quirk->codec_id && quirk->codec_id != ac97->id) continue; snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device); diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 06551a6..cafab4a 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1334,8 +1334,8 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *r static struct ac97_quirk ac97_quirks[] __devinitdata = { { - .vendor = 0x103c, - .device = 0x006b, + .subvendor = 0x103c, + .subdevice = 0x006b, .name = "HP Pavilion ZV5030US", .type = AC97_TUNE_MUTE_LED }, diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 4c47fc8..52d1074 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1560,51 +1560,51 @@ static void snd_via82xx_mixer_free_ac97(ac97_t *ac97) static struct ac97_quirk ac97_quirks[] = { { - .vendor = 0x1106, - .device = 0x4161, + .subvendor = 0x1106, + .subdevice = 0x4161, .codec_id = 0x56494161, /* VT1612A */ .name = "Soltek SL-75DRV5", .type = AC97_TUNE_NONE }, { /* FIXME: which codec? */ - .vendor = 0x1106, - .device = 0x4161, + .subvendor = 0x1106, + .subdevice = 0x4161, .name = "ASRock K7VT2", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1019, - .device = 0x0a81, + .subvendor = 0x1019, + .subdevice = 0x0a81, .name = "ECS K7VTA3", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1019, - .device = 0x0a85, + .subvendor = 0x1019, + .subdevice = 0x0a85, .name = "ECS L7VMM2", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1849, - .device = 0x3059, + .subvendor = 0x1849, + .subdevice = 0x3059, .name = "ASRock K7VM2", .type = AC97_TUNE_HP_ONLY /* VT1616 */ }, { - .vendor = 0x14cd, - .device = 0x7002, + .subvendor = 0x14cd, + .subdevice = 0x7002, .name = "Unknown", .type = AC97_TUNE_ALC_JACK }, { - .vendor = 0x1071, - .device = 0x8590, + .subvendor = 0x1071, + .subdevice = 0x8590, .name = "Mitac Mobo", .type = AC97_TUNE_ALC_JACK }, { - .vendor = 0x161f, - .device = 0x202b, + .subvendor = 0x161f, + .subdevice = 0x202b, .name = "Arima Notebook", .type = AC97_TUNE_HP_ONLY, }, @@ -2142,8 +2142,8 @@ static struct via823x_info via823x_cards[] __devinitdata = { * auto detection of DXS channel supports. */ struct dxs_whitelist { - unsigned short vendor; - unsigned short device; + unsigned short subvendor; + unsigned short subdevice; unsigned short mask; short action; /* new dxs_support value */ }; @@ -2151,43 +2151,43 @@ struct dxs_whitelist { static int __devinit check_dxs_list(struct pci_dev *pci) { static struct dxs_whitelist whitelist[] = { - { .vendor = 0x1005, .device = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */ - { .vendor = 0x1019, .device = 0x0996, .action = VIA_DXS_48K }, - { .vendor = 0x1019, .device = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */ - { .vendor = 0x1019, .device = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */ - { .vendor = 0x1025, .device = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */ - { .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ - { .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ - { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ - { .vendor = 0x1043, .device = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ - { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ - { .vendor = 0x1071, .device = 0x8399, .action = VIA_DXS_ENABLE }, /* Umax AB 595T (VIA K8N800A - VT8237) */ - { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ - { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ - { .vendor = 0x1106, .device = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ - { .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ - { .vendor = 0x1106, .device = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */ - { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ - { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ - { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ - { .vendor = 0x1462, .device = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */ - { .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ - { .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ - { .vendor = 0x1462, .device = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */ - { .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ - { .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */ - { .vendor = 0x147b, .device = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */ - { .vendor = 0x147b, .device = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */ - { .vendor = 0x147b, .device = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ - { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ - { .vendor = 0x14ff, .device = 0x0408, .action = VIA_DXS_NO_VRA }, /* Twinhead mobo */ - { .vendor = 0x1584, .device = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ - { .vendor = 0x1584, .device = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ - { .vendor = 0x161f, .device = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ - { .vendor = 0x161f, .device = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */ - { .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ - { .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ - { .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ + { .subvendor = 0x1005, .subdevice = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */ + { .subvendor = 0x1019, .subdevice = 0x0996, .action = VIA_DXS_48K }, + { .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */ + { .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */ + { .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */ + { .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ + { .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ + { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ + { .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ + { .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ + { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_ENABLE }, /* Umax AB 595T (VIA K8N800A - VT8237) */ + { .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ + { .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ + { .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ + { .subvendor = 0x1106, .subdevice = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ + { .subvendor = 0x1106, .subdevice = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */ + { .subvendor = 0x1297, .subdevice = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ + { .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ + { .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ + { .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */ + { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ + { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ + { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */ + { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ + { .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */ + { .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */ + { .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */ + { .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ + { .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ + { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_NO_VRA }, /* Twinhead mobo */ + { .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ + { .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ + { .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ + { .subvendor = 0x161f, .subdevice = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */ + { .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ + { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ + { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ { } /* terminator */ }; struct dxs_whitelist *w; @@ -2197,14 +2197,14 @@ static int __devinit check_dxs_list(struct pci_dev *pci) pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); - for (w = whitelist; w->vendor; w++) { - if (w->vendor != subsystem_vendor) + for (w = whitelist; w->subvendor; w++) { + if (w->subvendor != subsystem_vendor) continue; if (w->mask) { - if ((w->mask & subsystem_device) == w->device) + if ((w->mask & subsystem_device) == w->subdevice) return w->action; } else { - if (subsystem_device == w->device) + if (subsystem_device == w->subdevice) return w->action; } } -- cgit v0.10.2 From 6fd8b87f0e1e5de436ba020bd5806fe9ad738269 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Mon, 30 May 2005 17:20:19 +0200 Subject: [ALSA] AC97 - renamed vendor/device to subvendor/subdevice where appropriate Intel8x0 driver To avoid confusion, the structure members vendor/device were renamed to subvendor/subdevice, because we compare them with PCI subsystem vendor and subsystem device. Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 9c5710d..53fa5d8 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1725,229 +1725,229 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { static struct ac97_quirk ac97_quirks[] __devinitdata = { { - .vendor = 0x0e11, - .device = 0x008a, + .subvendor = 0x0e11, + .subdevice = 0x008a, .name = "Compaq Evo W4000", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x0e11, - .device = 0x00b8, + .subvendor = 0x0e11, + .subdevice = 0x00b8, .name = "Compaq Evo D510C", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x0e11, - .device = 0x0860, + .subvendor = 0x0e11, + .subdevice = 0x0860, .name = "HP/Compaq nx7010", .type = AC97_TUNE_MUTE_LED }, { - .vendor = 0x1014, - .device = 0x1f00, + .subvendor = 0x1014, + .subdevice = 0x1f00, .name = "MS-9128", .type = AC97_TUNE_ALC_JACK }, { - .vendor = 0x1028, - .device = 0x00d8, + .subvendor = 0x1028, + .subdevice = 0x00d8, .name = "Dell Precision 530", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x010d, + .subvendor = 0x1028, + .subdevice = 0x010d, .name = "Dell", /* which model? AD1885 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x0126, + .subvendor = 0x1028, + .subdevice = 0x0126, .name = "Dell Optiplex GX260", /* AD1981A */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x012c, + .subvendor = 0x1028, + .subdevice = 0x012c, .name = "Dell Precision 650", /* AD1981A */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x012d, + .subvendor = 0x1028, + .subdevice = 0x012d, .name = "Dell Precision 450", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x0147, + .subvendor = 0x1028, + .subdevice = 0x0147, .name = "Dell", /* which model? AD1981B*/ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x0163, + .subvendor = 0x1028, + .subdevice = 0x0163, .name = "Dell Unknown", /* STAC9750/51 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x006d, + .subvendor = 0x103c, + .subdevice = 0x006d, .name = "HP zv5000", .type = AC97_TUNE_MUTE_LED /*AD1981B*/ }, { /* FIXME: which codec? */ - .vendor = 0x103c, - .device = 0x00c3, + .subvendor = 0x103c, + .subdevice = 0x00c3, .name = "HP xw6000", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x088c, + .subvendor = 0x103c, + .subdevice = 0x088c, .name = "HP nc8000", .type = AC97_TUNE_MUTE_LED }, { - .vendor = 0x103c, - .device = 0x0890, + .subvendor = 0x103c, + .subdevice = 0x0890, .name = "HP nc6000", .type = AC97_TUNE_MUTE_LED }, { - .vendor = 0x103c, - .device = 0x129d, + .subvendor = 0x103c, + .subdevice = 0x129d, .name = "HP xw8000", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x12f1, + .subvendor = 0x103c, + .subdevice = 0x12f1, .name = "HP xw8200", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x12f2, + .subvendor = 0x103c, + .subdevice = 0x12f2, .name = "HP xw6200", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x3008, + .subvendor = 0x103c, + .subdevice = 0x3008, .name = "HP xw4200", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x104d, - .device = 0x8197, + .subvendor = 0x104d, + .subdevice = 0x8197, .name = "Sony S1XP", .type = AC97_TUNE_INV_EAPD }, { - .vendor = 0x1043, - .device = 0x80f3, + .subvendor = 0x1043, + .subdevice = 0x80f3, .name = "ASUS ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x10cf, - .device = 0x11c3, + .subvendor = 0x10cf, + .subdevice = 0x11c3, .name = "Fujitsu-Siemens E4010", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x10cf, - .device = 0x1253, + .subvendor = 0x10cf, + .subdevice = 0x1253, .name = "Fujitsu S6210", /* STAC9750/51 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x10f1, - .device = 0x2665, + .subvendor = 0x10f1, + .subdevice = 0x2665, .name = "Fujitsu-Siemens Celsius", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x10f1, - .device = 0x2885, + .subvendor = 0x10f1, + .subdevice = 0x2885, .name = "AMD64 Mobo", /* ALC650 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x110a, - .device = 0x0056, + .subvendor = 0x110a, + .subdevice = 0x0056, .name = "Fujitsu-Siemens Scenic", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x11d4, - .device = 0x5375, + .subvendor = 0x11d4, + .subdevice = 0x5375, .name = "ADI AD1985 (discrete)", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1462, - .device = 0x5470, + .subvendor = 0x1462, + .subdevice = 0x5470, .name = "MSI P4 ATX 645 Ultra", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1734, - .device = 0x0088, + .subvendor = 0x1734, + .subdevice = 0x0088, .name = "Fujitsu-Siemens D1522", /* AD1981 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x8086, - .device = 0x2000, + .subvendor = 0x8086, + .subdevice = 0x2000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x8086, - .device = 0x4000, + .subvendor = 0x8086, + .subdevice = 0x4000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x8086, - .device = 0x4856, + .subvendor = 0x8086, + .subdevice = 0x4856, .name = "Intel D845WN (82801BA)", .type = AC97_TUNE_SWAP_HP }, { - .vendor = 0x8086, - .device = 0x4d44, + .subvendor = 0x8086, + .subdevice = 0x4d44, .name = "Intel D850EMV2", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x8086, - .device = 0x4d56, + .subvendor = 0x8086, + .subdevice = 0x4d56, .name = "Intel ICH/AD1885", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x8086, - .device = 0x6000, + .subvendor = 0x8086, + .subdevice = 0x6000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x8086, - .device = 0xe000, + .subvendor = 0x8086, + .subdevice = 0xe000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, #if 0 /* FIXME: this seems wrong on most boards */ { - .vendor = 0x8086, - .device = 0xa000, + .subvendor = 0x8086, + .subdevice = 0xa000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_HP_ONLY -- cgit v0.10.2 From 4d572776d4dfa2d5385a2ec3acec3cc059149e13 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 30 May 2005 17:30:32 +0200 Subject: [ALSA] Remove redundant NULL checks before kfree Timer Midlevel,ALSA sequencer,ALSA<-OSS sequencer,Digigram VX core I2C tea6330t,GUS Library,VIA82xx driver,VIA82xx-modem driver CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,YMFPCI driver Digigram VX Pocket driver,Common EMU synth,USB generic driver,USB USX2Y Checking a pointer for NULL before calling kfree() on it is redundant, kfree() deals with NULL pointers just fine. This patch removes such checks from sound/ This patch also makes another, but closely related, change. It avoids casting pointers about to be kfree()'ed. Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 638cc14..1a7736c 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -325,14 +325,10 @@ snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp) } snd_use_lock_free(&rec->use_lock); } - if (info->sysex) { - kfree(info->sysex); - info->sysex = NULL; - } - if (info->ch) { - kfree(info->ch); - info->ch = NULL; - } + kfree(info->sysex); + info->sysex = NULL; + kfree(info->ch); + info->ch = NULL; } dp->synth_opened = 0; dp->max_synthdev = 0; @@ -418,14 +414,10 @@ snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev) dp->file_mode) < 0) { midi_synth_dev.opened--; info->opened = 0; - if (info->sysex) { - kfree(info->sysex); - info->sysex = NULL; - } - if (info->ch) { - kfree(info->ch); - info->ch = NULL; - } + kfree(info->sysex); + info->sysex = NULL; + kfree(info->ch); + info->ch = NULL; } return; } diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index e88967c..ea945a5 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -140,10 +140,7 @@ dummy_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int static void dummy_free(void *private_data) { - snd_seq_dummy_port_t *p; - - p = private_data; - kfree(p); + kfree(private_data); } /* diff --git a/sound/core/timer.c b/sound/core/timer.c index d67a5e9..b498e54 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1469,14 +1469,10 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0) goto __err; - if (tu->queue) { - kfree(tu->queue); - tu->queue = NULL; - } - if (tu->tqueue) { - kfree(tu->tqueue); - tu->tqueue = NULL; - } + kfree(tu->queue); + tu->queue = NULL; + kfree(tu->tqueue); + tu->tqueue = NULL; if (tu->tread) { tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); if (tu->tqueue == NULL) diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 9858717..af381b1 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -1264,14 +1264,10 @@ static void snd_vx_pcm_free(snd_pcm_t *pcm) { vx_core_t *chip = pcm->private_data; chip->pcm[pcm->device] = NULL; - if (chip->playback_pipes) { - kfree(chip->playback_pipes); - chip->playback_pipes = NULL; - } - if (chip->capture_pipes) { - kfree(chip->capture_pipes); - chip->capture_pipes = NULL; - } + kfree(chip->playback_pipes); + chip->playback_pipes = NULL; + kfree(chip->capture_pipes); + chip->capture_pipes = NULL; } /* diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c index bb503e7..2da8d7f 100644 --- a/sound/i2c/tea6330t.c +++ b/sound/i2c/tea6330t.c @@ -266,8 +266,7 @@ TEA6330T_TREBLE("Tone Control - Treble", 0) static void snd_tea6330_free(snd_i2c_device_t *device) { - tea6330t_t *tea = device->private_data; - kfree(tea); + kfree(device->private_data); } int snd_tea6330t_update_mixer(snd_card_t * card, diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 8995ad9..b75066a 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -656,8 +656,7 @@ static snd_pcm_hardware_t snd_gf1_pcm_capture = static void snd_gf1_pcm_playback_free(snd_pcm_runtime_t *runtime) { - gus_pcm_private_t * pcmp = runtime->private_data; - kfree(pcmp); + kfree(runtime->private_data); } static int snd_gf1_pcm_playback_open(snd_pcm_substream_t *substream) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 85caf1b..0ec0c3e 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -332,11 +332,7 @@ static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) static void snd_ca0106_pcm_free_substream(snd_pcm_runtime_t *runtime) { - ca0106_pcm_t *epcm = runtime->private_data; - - if (epcm) { - kfree(epcm); - } + kfree(runtime->private_data); } /* open_playback callback */ diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 5f2ffb7..fd4c50c 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1295,8 +1295,7 @@ static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime) { - cs46xx_pcm_t * cpcm = runtime->private_data; - kfree(cpcm); + kfree(runtime->private_data); } static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id) diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index f8d9233..e90c5ddd 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -361,10 +361,7 @@ static void snd_emu10k1x_gpio_write(emu10k1x_t *emu, unsigned int value) static void snd_emu10k1x_pcm_free_substream(snd_pcm_runtime_t *runtime) { - emu10k1x_pcm_t *epcm = runtime->private_data; - - if (epcm) - kfree(epcm); + kfree(runtime->private_data); } static void snd_emu10k1x_pcm_interrupt(emu10k1x_t *emu, emu10k1x_voice_t *voice) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index fd7cc38..520b99a 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -991,9 +991,7 @@ static void snd_emu10k1_pcm_efx_mixer_notify(emu10k1_t *emu, int idx, int activa static void snd_emu10k1_pcm_free_substream(snd_pcm_runtime_t *runtime) { - emu10k1_pcm_t *epcm = runtime->private_data; - - kfree(epcm); + kfree(runtime->private_data); } static int snd_emu10k1_efx_playback_close(snd_pcm_substream_t * substream) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 52d1074..e329e19 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -491,10 +491,8 @@ static int clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream, snd_dma_free_pages(&dev->table); dev->table.area = NULL; } - if (dev->idx_table) { - kfree(dev->idx_table); - dev->idx_table = NULL; - } + kfree(dev->idx_table); + dev->idx_table = NULL; return 0; } diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index e10fceb..5896d28 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -352,10 +352,8 @@ static int clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream, snd_dma_free_pages(&dev->table); dev->table.area = NULL; } - if (dev->idx_table) { - kfree(dev->idx_table); - dev->idx_table = NULL; - } + kfree(dev->idx_table); + dev->idx_table = NULL; return 0; } diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 997cf37..2ae7961 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -829,9 +829,7 @@ static snd_pcm_hardware_t snd_ymfpci_capture = static void snd_ymfpci_pcm_free_substream(snd_pcm_runtime_t *runtime) { - ymfpci_pcm_t *ypcm = runtime->private_data; - - kfree(ypcm); + kfree(runtime->private_data); } static int snd_ymfpci_playback_open_1(snd_pcm_substream_t * substream) diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c index 53d8172..332bbca 100644 --- a/sound/pcmcia/vx/vx_entry.c +++ b/sound/pcmcia/vx/vx_entry.c @@ -68,8 +68,7 @@ static int snd_vxpocket_free(vx_core_t *chip) if (hw) hw->card_list[vxp->index] = NULL; chip->card = NULL; - if (chip->dev) - kfree(chip->dev); + kfree(chip->dev); snd_vx_free_firmware(chip); kfree(chip); diff --git a/sound/synth/emux/emux_effect.c b/sound/synth/emux/emux_effect.c index ec3fc1b..4764940 100644 --- a/sound/synth/emux/emux_effect.c +++ b/sound/synth/emux/emux_effect.c @@ -291,10 +291,8 @@ snd_emux_create_effect(snd_emux_port_t *p) void snd_emux_delete_effect(snd_emux_port_t *p) { - if (p->effect) { - kfree(p->effect); - p->effect = NULL; - } + kfree(p->effect); + p->effect = NULL; } void diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a82412b..a756950 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -859,10 +859,8 @@ static void release_urb_ctx(snd_urb_ctx_t *u) usb_free_urb(u->urb); u->urb = NULL; } - if (u->buf) { - kfree(u->buf); - u->buf = NULL; - } + kfree(u->buf); + u->buf = NULL; } /* @@ -880,10 +878,8 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force) release_urb_ctx(&subs->dataurb[i]); for (i = 0; i < SYNC_URBS; i++) release_urb_ctx(&subs->syncurb[i]); - if (subs->tmpbuf) { - kfree(subs->tmpbuf); - subs->tmpbuf = NULL; - } + kfree(subs->tmpbuf); + subs->tmpbuf = NULL; subs->nurbs = 0; } diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 83ba665..e73c1c9 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -623,10 +623,8 @@ static struct usb_feature_control_info audio_feature_info[] = { /* private_free callback */ static void usb_mixer_elem_free(snd_kcontrol_t *kctl) { - if (kctl->private_data) { - kfree(kctl->private_data); - kctl->private_data = NULL; - } + kfree(kctl->private_data); + kctl->private_data = NULL; } diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 4c292e0..62dfd28 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -401,10 +401,8 @@ static void usX2Y_urbs_release(snd_usX2Y_substream_t *subs) for (i = 0; i < NRURBS; i++) usX2Y_urb_release(subs->urb + i, subs != subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]); - if (subs->tmpbuf) { - kfree(subs->tmpbuf); - subs->tmpbuf = NULL; - } + kfree(subs->tmpbuf); + subs->tmpbuf = NULL; } /* * initialize a substream's urbs -- cgit v0.10.2 From b6a969155b04416185f368bd4e2f1d49b17c1ee1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 May 2005 18:27:03 +0200 Subject: [ALSA] Add write support to snd-page-alloc proc file Documentation,Memalloc module,RME HDSP driver,RME9652 driver Add the write support to snd-page-alloc proc file for buffer pre-allocation. Removed the pre-allocation codes via module options. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 2260130..812ed2b 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -671,7 +671,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. module did formerly. It will allocate the buffers in advance when any HDSP cards are found. To make the buffer allocation sure, load snd-page-alloc module in the early - stage of boot sequence. + stage of boot sequence. See "Early Buffer Allocation" + section. Module snd-ice1712 ------------------ @@ -1067,7 +1068,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. module did formerly. It will allocate the buffers in advance when any RME9652 cards are found. To make the buffer allocation sure, load snd-page-alloc module in the early - stage of boot sequence. + stage of boot sequence. See "Early Buffer Allocation" + section. Module snd-sa11xx-uda1341 (on arm only) --------------------------------------- @@ -1545,6 +1547,36 @@ Proc interfaces (/proc/asound) echo "rvplayer 0 0 block" > /proc/asound/card0/pcm0p/oss +Early Buffer Allocation +======================= + +Some drivers (e.g. hdsp) require the large contiguous buffers, and +sometimes it's too late to find such spaces when the driver module is +actually loaded due to memory fragmentation. You can pre-allocate the +PCM buffers by loading snd-page-alloc module and write commands to its +proc file in prior, for example, in the early boot stage like +/etc/init.d/*.local scripts. + +Reading the proc file /proc/drivers/snd-page-alloc shows the current +usage of page allocation. In writing, you can send the following +commands to the snd-page-alloc driver: + + - add VENDOR DEVICE MASK SIZE BUFFERS + + VENDOR and DEVICE are PCI vendor and device IDs. They take + integer numbers (0x prefix is needed for the hex). + MASK is the PCI DMA mask. Pass 0 if not restricted. + SIZE is the size of each buffer to allocate. You can pass + k and m suffix for KB and MB. The max number is 16MB. + BUFFERS is the number of buffers to allocate. It must be greater + than 0. The max number is 4. + + - erase + + This will erase the all pre-allocated buffers which are not in + use. + + Links ===== diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 344a83f..dbc23e3 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -46,13 +47,6 @@ MODULE_LICENSE("GPL"); #define SNDRV_CARDS 8 #endif -/* FIXME: so far only some PCI devices have the preallocation table */ -#ifdef CONFIG_PCI -static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable cards to allocate buffers."); -#endif - /* */ @@ -451,9 +445,13 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) list_for_each(p, &mem_list_head) { mem = list_entry(p, struct snd_mem_list, list); if (mem->id == id && - ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev))) { + (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL || + ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) { + struct device *dev = dmab->dev.dev; list_del(p); *dmab = mem->buffer; + if (dmab->dev.dev == NULL) + dmab->dev.dev = dev; kfree(mem); up(&list_mutex); return dmab->bytes; @@ -508,91 +506,13 @@ static void free_all_reserved_pages(void) } - -/* - * allocation of buffers for pre-defined devices - */ - -#ifdef CONFIG_PCI -/* FIXME: for pci only - other bus? */ -struct prealloc_dev { - unsigned short vendor; - unsigned short device; - unsigned long dma_mask; - unsigned int size; - unsigned int buffers; -}; - -#define HAMMERFALL_BUFFER_SIZE (16*1024*4*(26+1)+0x10000) - -static struct prealloc_dev prealloc_devices[] __initdata = { - { - /* hammerfall */ - .vendor = 0x10ee, - .device = 0x3fc4, - .dma_mask = 0xffffffff, - .size = HAMMERFALL_BUFFER_SIZE, - .buffers = 2 - }, - { - /* HDSP */ - .vendor = 0x10ee, - .device = 0x3fc5, - .dma_mask = 0xffffffff, - .size = HAMMERFALL_BUFFER_SIZE, - .buffers = 2 - }, - { }, /* terminator */ -}; - -static void __init preallocate_cards(void) -{ - struct pci_dev *pci = NULL; - int card; - - card = 0; - - while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { - struct prealloc_dev *dev; - unsigned int i; - if (card >= SNDRV_CARDS) - break; - for (dev = prealloc_devices; dev->vendor; dev++) { - if (dev->vendor == pci->vendor && dev->device == pci->device) - break; - } - if (! dev->vendor) - continue; - if (! enable[card++]) { - printk(KERN_DEBUG "snd-page-alloc: skipping card %d, device %04x:%04x\n", card, pci->vendor, pci->device); - continue; - } - - if (pci_set_dma_mask(pci, dev->dma_mask) < 0 || - pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) { - printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device); - continue; - } - for (i = 0; i < dev->buffers; i++) { - struct snd_dma_buffer dmab; - memset(&dmab, 0, sizeof(dmab)); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - dev->size, &dmab) < 0) - printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size); - else - snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); - } - } -} -#else -#define preallocate_cards() /* NOP */ -#endif - - #ifdef CONFIG_PROC_FS /* * proc file interface */ +#define SND_MEM_PROC_FILE "driver/snd-page-alloc" +struct proc_dir_entry *snd_mem_proc; + static int snd_mem_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -621,6 +541,97 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, up(&list_mutex); return len; } + +/* FIXME: for pci only - other bus? */ +#ifdef CONFIG_PCI +#define gettoken(bufp) strsep(bufp, " \t\n") + +static int snd_mem_proc_write(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + char buf[128]; + char *token, *p; + + if (count > ARRAY_SIZE(buf) - 1) + count = ARRAY_SIZE(buf) - 1; + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + buf[ARRAY_SIZE(buf) - 1] = '\0'; + + p = buf; + token = gettoken(&p); + if (! token || *token == '#') + return (int)count; + if (strcmp(token, "add") == 0) { + char *endp; + int vendor, device, size, buffers; + long mask; + int i, alloced; + struct pci_dev *pci; + + if ((token = gettoken(&p)) == NULL || + (vendor = simple_strtol(token, NULL, 0)) <= 0 || + (token = gettoken(&p)) == NULL || + (device = simple_strtol(token, NULL, 0)) <= 0 || + (token = gettoken(&p)) == NULL || + (mask = simple_strtol(token, NULL, 0)) < 0 || + (token = gettoken(&p)) == NULL || + (size = memparse(token, &endp)) < 64*1024 || + size > 16*1024*1024 /* too big */ || + (token = gettoken(&p)) == NULL || + (buffers = simple_strtol(token, NULL, 0)) <= 0 || + buffers > 4) { + printk(KERN_ERR "snd-page-alloc: invalid proc write format\n"); + return (int)count; + } + vendor &= 0xffff; + device &= 0xffff; + + alloced = 0; + pci = NULL; + while ((pci = pci_find_device(vendor, device, pci)) != NULL) { + if (mask > 0 && mask < 0xffffffff) { + if (pci_set_dma_mask(pci, mask) < 0 || + pci_set_consistent_dma_mask(pci, mask) < 0) { + printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device); + return (int)count; + } + } + for (i = 0; i < buffers; i++) { + struct snd_dma_buffer dmab; + memset(&dmab, 0, sizeof(dmab)); + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + size, &dmab) < 0) { + printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); + return (int)count; + } + snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); + } + alloced++; + } + if (! alloced) { + for (i = 0; i < buffers; i++) { + struct snd_dma_buffer dmab; + memset(&dmab, 0, sizeof(dmab)); + /* FIXME: We can allocate only in ZONE_DMA + * without a device pointer! + */ + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL, + size, &dmab) < 0) { + printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); + break; + } + snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device)); + } + } + } else if (strcmp(token, "erase") == 0) + /* FIXME: need for releasing each buffer chunk? */ + free_all_reserved_pages(); + else + printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n"); + return (int)count; +} +#endif /* CONFIG_PCI */ #endif /* CONFIG_PROC_FS */ /* @@ -630,15 +641,21 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, static int __init snd_mem_init(void) { #ifdef CONFIG_PROC_FS - create_proc_read_entry("driver/snd-page-alloc", 0, NULL, snd_mem_proc_read, NULL); + snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL); + if (snd_mem_proc) { + snd_mem_proc->read_proc = snd_mem_proc_read; +#ifdef CONFIG_PCI + snd_mem_proc->write_proc = snd_mem_proc_write; +#endif + } #endif - preallocate_cards(); return 0; } static void __exit snd_mem_exit(void) { - remove_proc_entry("driver/snd-page-alloc", NULL); + if (snd_mem_proc) + remove_proc_entry(SND_MEM_PROC_FILE, NULL); free_all_reserved_pages(); if (snd_allocated_pages > 0) printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index b35ed5f..a673cc4 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -559,18 +559,22 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer { dmab->dev.type = SNDRV_DMA_TYPE_DEV; dmab->dev.dev = snd_dma_pci_data(pci); - if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - size, dmab) < 0) - return -ENOMEM; + if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { + if (dmab->bytes >= size) + return 0; } + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + size, dmab) < 0) + return -ENOMEM; return 0; } static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) { - if (dmab->area) + if (dmab->area) { + dmab->dev.dev = NULL; /* make it anonymous */ snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); + } } diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 5861f23..f303740 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -303,18 +303,22 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer { dmab->dev.type = SNDRV_DMA_TYPE_DEV; dmab->dev.dev = snd_dma_pci_data(pci); - if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - size, dmab) < 0) - return -ENOMEM; + if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { + if (dmab->bytes >= size) + return 0; } + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + size, dmab) < 0) + return -ENOMEM; return 0; } static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) { - if (dmab->area) + if (dmab->area) { + dmab->dev.dev = NULL; /* make it anonymous */ snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); + } } -- cgit v0.10.2 From ce43fbaececc82196d321671159483b3287de128 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 May 2005 20:33:44 +0200 Subject: [ALSA] hda-intel - Fix Oops in the error path HDA Intel driver Fixed Oops in the error path from probe function of snd-hda-intel driver. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f05a638..0d546ad 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -286,6 +286,7 @@ struct snd_azx { /* flags */ int position_fix; + unsigned int initialized: 1; }; /* @@ -1235,7 +1236,7 @@ static int azx_resume(snd_card_t *card) */ static int azx_free(azx_t *chip) { - if (chip->remap_addr) { + if (chip->initialized) { int i; for (i = 0; i < MAX_ICH6_DEV; i++) @@ -1361,6 +1362,8 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, /* initialize chip */ azx_init_chip(chip); + chip->initialized = 1; + /* codec detection */ if (! chip->codec_mask) { snd_printk(KERN_ERR SFX "no codecs found!\n"); -- cgit v0.10.2 From 21cb2a2ec5818cbba01bcb7f24388670322c77f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 May 2005 14:35:31 +0200 Subject: [ALSA] Fix races between PCM drain and other ops PCM Midlevel Fix semaphore races between PCM drain and other ops. Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 4e58241..10c2c98 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1368,43 +1368,32 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - down_read(&snd_pcm_link_rwsem); snd_power_lock(card); if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); - if (result < 0) - goto _unlock; + if (result < 0) { + snd_power_unlock(card); + return result; + } } /* allocate temporary record for drain sync */ + down_read(&snd_pcm_link_rwsem); if (snd_pcm_stream_linked(substream)) { drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL); if (! drec) { - result = -ENOMEM; - goto _unlock; + up_read(&snd_pcm_link_rwsem); + snd_power_unlock(card); + return -ENOMEM; } } else drec = &drec_tmp; - snd_pcm_stream_lock_irq(substream); - /* resume pause */ - if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) - snd_pcm_pause(substream, 0); - - /* pre-start/stop - all running streams are changed to DRAINING state */ - result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); - if (result < 0) - goto _end; - - /* check streams with PLAYBACK & DRAINING */ + /* count only playback streams */ num_drecs = 0; snd_pcm_group_for_each(pos, substream) { snd_pcm_substream_t *s = snd_pcm_group_substream_entry(pos); runtime = s->runtime; - if (runtime->status->state != SNDRV_PCM_STATE_DRAINING) { - runtime->status->state = SNDRV_PCM_STATE_SETUP; - continue; - } if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { d = &drec[num_drecs++]; d->substream = s; @@ -1418,9 +1407,21 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) runtime->stop_threshold = runtime->buffer_size; } } - + up_read(&snd_pcm_link_rwsem); if (! num_drecs) - goto _end; + goto _error; + + snd_pcm_stream_lock_irq(substream); + /* resume pause */ + if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) + snd_pcm_pause(substream, 0); + + /* pre-start/stop - all running streams are changed to DRAINING state */ + result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); + if (result < 0) { + snd_pcm_stream_unlock_irq(substream); + goto _error; + } for (;;) { long tout; @@ -1428,6 +1429,15 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) result = -ERESTARTSYS; break; } + /* all finished? */ + for (i = 0; i < num_drecs; i++) { + runtime = drec[i].substream->runtime; + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) + break; + } + if (i == num_drecs) + break; /* yes, all drained */ + set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); snd_power_unlock(card); @@ -1444,15 +1454,11 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) } break; } - /* all finished? */ - for (i = 0; i < num_drecs; i++) { - runtime = drec[i].substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) - break; - } - if (i == num_drecs) - break; } + + snd_pcm_stream_unlock_irq(substream); + + _error: for (i = 0; i < num_drecs; i++) { d = &drec[i]; runtime = d->substream->runtime; @@ -1460,13 +1466,9 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) runtime->stop_threshold = d->stop_threshold; } - _end: - snd_pcm_stream_unlock_irq(substream); if (drec != &drec_tmp) kfree(drec); - _unlock: snd_power_unlock(card); - up_read(&snd_pcm_link_rwsem); return result; } -- cgit v0.10.2 From fb4bd0adc4b5b6538933b098a67851d8f99b5ca3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 31 May 2005 15:44:23 +0200 Subject: [ALSA] OSS PCM emulation - The final fix for SNDCTL_DSP_GETOPTR problem ALSA<-OSS emulation The problem was negative result (info.bytes) in a specific condition at playback startup. Signed-off-by: Jaroslav Kysela diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 468fca8..203470d 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1539,10 +1539,13 @@ static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, str } else { delay = snd_pcm_oss_bytes(substream, delay) + fixup; info.blocks = delay / runtime->oss.period_bytes; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (runtime->oss.bytes == 0) + delay = 0; info.bytes = (runtime->oss.bytes - delay) & INT_MAX; - else + } else { info.bytes = (runtime->oss.bytes + delay) & INT_MAX; + } } if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; -- cgit v0.10.2 From 98c7f2121d4263867710df3b5124980e25261188 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 May 2005 16:52:58 +0200 Subject: [ALSA] Add FSC T3010 quirk Intel8x0 driver Added ac97_quirk for FSC T3010. Signed-off-by: Takashi Iwai diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 53fa5d8..cc16f95 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1858,6 +1858,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { }, { .subvendor = 0x10cf, + .subdevice = 0x1225, + .name = "Fujitsu-Siemens T3010", + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x10cf, .subdevice = 0x1253, .name = "Fujitsu S6210", /* STAC9750/51 */ .type = AC97_TUNE_HP_ONLY -- cgit v0.10.2 From 5ac0fab95c09497bed24640eb3f09893127d6d65 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 31 May 2005 16:59:39 +0200 Subject: [ALSA] OSS PCM emulation - The 2nd final fix for SNDCTL_DSP_GETOPTR problem ALSA<-OSS emulation The problem was negative/wrong result (info.bytes) in a specific condition at playback startup. Signed-off-by: Jaroslav Kysela diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 203470d..cab3097 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1537,13 +1537,13 @@ static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, str snd_pcm_oss_simulate_fill(substream, delay); info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; } else { - delay = snd_pcm_oss_bytes(substream, delay) + fixup; - info.blocks = delay / runtime->oss.period_bytes; + delay = snd_pcm_oss_bytes(substream, delay); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (runtime->oss.bytes == 0) - delay = 0; + info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes; info.bytes = (runtime->oss.bytes - delay) & INT_MAX; } else { + delay += fixup; + info.blocks = delay / runtime->oss.period_bytes; info.bytes = (runtime->oss.bytes + delay) & INT_MAX; } } -- cgit v0.10.2 From 375389288ae55754bd7d009a30f2bb0453a5b369 Mon Sep 17 00:00:00 2001 From: Christoph Schulz Date: Fri, 3 Jun 2005 08:28:31 +0200 Subject: [ALSA] cs4236-irq-handling-fix.patch CS4236+ driver Background: The card/chipset supports an external MIDI interrupt. By default, this interrupt isn't used (because the isapnp mechanism chooses a configuration without an assigned interrupt). If the user wishes to explicitly select an interrupt via the mpu_irq parameter for such a configured device, it doesn't work: The driver always shows: isapnp MPU: port=0x330, irq=-1 (note the 'irq=-1') Problem: The driver only allows to set the irq if pnp_irq_valid returns true for this particular pnp device. This, however, is only true if an interrupt has already been assigned (pnp_valid_irq returns true if the flag IORESOURCE_IRQ is set and IORESOURCE_UNSET is not set). If no interrupt has been assigned so far, IORESOURCE_UNSET is set and pnp_irq_valid returns false, thereby inhibiting the selection of a valid irq. Solution: Don't check for a valid (= already assigned) irq at the point of calling pnp_resource_change. Tested successfully on Linux 2.6.11. Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index e745a54..39f4eff 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -349,8 +349,7 @@ static int __devinit snd_card_cs4236_pnp(int dev, struct snd_card_cs4236 *acard, pnp_init_resource_table(cfg); if (mpu_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); - if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0 && - pnp_irq_valid(pdev, 0)) + if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0) pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); err = pnp_manual_config_dev(pdev, cfg, 0); if (err < 0) -- cgit v0.10.2 From 763f356cd8de9e158836d236b3fd9dd149d696f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 3 Jun 2005 11:25:34 +0200 Subject: [ALSA] Add HDSP MADI driver HDSPM driver,PCI drivers,RME9652 driver Added RME Hammerfall DSP MADI driver by Winfried Ritsch. (Moved from alsa-driver tree to mainline.) Signed-off-by: Takashi Iwai diff --git a/include/sound/hdspm.h b/include/sound/hdspm.h new file mode 100644 index 0000000..c34427c --- /dev/null +++ b/include/sound/hdspm.h @@ -0,0 +1,131 @@ +#ifndef __SOUND_HDSPM_H /* -*- linux-c -*- */ +#define __SOUND_HDSPM_H +/* + * Copyright (C) 2003 Winfried Ritsch (IEM) + * based on hdsp.h from Thomas Charbonnel (thomas@undata.org) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */ +#define HDSPM_MAX_CHANNELS 64 + +/* -------------------- IOCTL Peak/RMS Meters -------------------- */ + +typedef struct _snd_hdspm_peak_rms hdspm_peak_rms_t; + +/* peam rms level structure like we get from hardware + + maybe in future we can memory map it so I just copy it + to user on ioctl call now an dont change anything + rms are made out of low and high values + where (long) ????_rms = (????_rms_l >> 8) + ((????_rms_h & 0xFFFFFF00)<<24) + (i asume so from the code) +*/ + +struct _snd_hdspm_peak_rms { + + unsigned int level_offset[1024]; + + unsigned int input_peak[64]; + unsigned int playback_peak[64]; + unsigned int output_peak[64]; + unsigned int xxx_peak[64]; /* not used */ + + unsigned int reserved[256]; /* not used */ + + unsigned int input_rms_l[64]; + unsigned int playback_rms_l[64]; + unsigned int output_rms_l[64]; + unsigned int xxx_rms_l[64]; /* not used */ + + unsigned int input_rms_h[64]; + unsigned int playback_rms_h[64]; + unsigned int output_rms_h[64]; + unsigned int xxx_rms_h[64]; /* not used */ +}; + +struct sndrv_hdspm_peak_rms_ioctl { + hdspm_peak_rms_t *peak; +}; + +/* use indirect access due to the limit of ioctl bit size */ +#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, struct sndrv_hdspm_peak_rms_ioctl) + +/* ------------ CONFIG block IOCTL ---------------------- */ + +typedef struct _snd_hdspm_config_info hdspm_config_info_t; + +struct _snd_hdspm_config_info { + unsigned char pref_sync_ref; + unsigned char wordclock_sync_check; + unsigned char madi_sync_check; + unsigned int system_sample_rate; + unsigned int autosync_sample_rate; + unsigned char system_clock_mode; + unsigned char clock_source; + unsigned char autosync_ref; + unsigned char line_out; + unsigned int passthru; + unsigned int analog_out; +}; + +#define SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, hdspm_config_info_t) + + +/* get Soundcard Version */ + +typedef struct _snd_hdspm_version hdspm_version_t; + +struct _snd_hdspm_version { + unsigned short firmware_rev; +}; + +#define SNDRV_HDSPM_IOCTL_GET_VERSION _IOR('H', 0x43, hdspm_version_t) + + +/* ------------- get Matrix Mixer IOCTL --------------- */ + +/* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte = 32768 Bytes */ + +/* organisation is 64 channelfader in a continous memory block */ +/* equivalent to hardware definition, maybe for future feature of mmap of them */ +/* each of 64 outputs has 64 infader and 64 outfader: + Ins to Outs mixer[out].in[in], Outstreams to Outs mixer[out].pb[pb] */ + +#define HDSPM_MIXER_CHANNELS HDSPM_MAX_CHANNELS + +typedef struct _snd_hdspm_channelfader snd_hdspm_channelfader_t; + +struct _snd_hdspm_channelfader { + unsigned int in[HDSPM_MIXER_CHANNELS]; + unsigned int pb[HDSPM_MIXER_CHANNELS]; +}; + +typedef struct _snd_hdspm_mixer hdspm_mixer_t; + +struct _snd_hdspm_mixer { + snd_hdspm_channelfader_t ch[HDSPM_MIXER_CHANNELS]; +}; + +struct sndrv_hdspm_mixer_ioctl { + hdspm_mixer_t *mixer; +}; + +/* use indirect access due to the limit of ioctl bit size */ +#define SNDRV_HDSPM_IOCTL_GET_MIXER _IOR('H', 0x44, struct sndrv_hdspm_mixer_ioctl) + +#endif /* __SOUND_HDSPM_H */ diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 428efdb..6d7a00f 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -274,6 +274,19 @@ config SND_HDSP To compile this driver as a module, choose M here: the module will be called snd-hdsp. +config SND_HDSPM + tristate "RME Hammerfall DSP MADI" + depends on SND + select SND_HWDEP + select SND_RAWMIDI + select SND_PCM + help + Say Y here to include support for RME Hammerfall DSP MADI + soundcards. + + To compile this driver as a module, choose M here: the module + will be called snd-hdspm. + config SND_TRIDENT tristate "Trident 4D-Wave DX/NX; SiS 7018" depends on SND diff --git a/sound/pci/rme9652/Makefile b/sound/pci/rme9652/Makefile index 917374c..d2c294e 100644 --- a/sound/pci/rme9652/Makefile +++ b/sound/pci/rme9652/Makefile @@ -5,7 +5,9 @@ snd-rme9652-objs := rme9652.o snd-hdsp-objs := hdsp.o +snd-hdspm-objs := hdspm.o # Toplevel Module Dependency obj-$(CONFIG_SND_RME9652) += snd-rme9652.o obj-$(CONFIG_SND_HDSP) += snd-hdsp.o +obj-$(CONFIG_SND_HDSPM) +=snd-hdspm.o diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c new file mode 100644 index 0000000..9e86d0e --- /dev/null +++ b/sound/pci/rme9652/hdspm.c @@ -0,0 +1,3671 @@ +/* -*- linux-c -*- + * + * ALSA driver for RME Hammerfall DSP MADI audio interface(s) + * + * Copyright (c) 2003 Winfried Ritsch (IEM) + * code based on hdsp.c Paul Davis + * Marcus Andersson + * Thomas Charbonnel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ + +/* Disable precise pointer at start */ +static int precise_ptr[SNDRV_CARDS]; + +/* Send all playback to line outs */ +static int line_outs_monitor[SNDRV_CARDS]; + +/* Enable Analog Outs on Channel 63/64 by default */ +static int enable_monitor[SNDRV_CARDS]; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for RME HDSPM interface."); + +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for RME HDSPM interface."); + +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards."); + +module_param_array(precise_ptr, bool, NULL, 0444); +MODULE_PARM_DESC(precise_ptr, "Enable precise pointer, or disable."); + +module_param_array(line_outs_monitor, bool, NULL, 0444); +MODULE_PARM_DESC(line_outs_monitor, + "Send playback streams to analog outs by default."); + +module_param_array(enable_monitor, bool, NULL, 0444); +MODULE_PARM_DESC(enable_monitor, + "Enable Analog Out on Channel 63/64 by default."); + +MODULE_AUTHOR + ("Winfried Ritsch , Paul Davis , " + "Marcus Andersson, Thomas Charbonnel "); +MODULE_DESCRIPTION("RME HDSPM"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); + +/* --- Write registers. --- + These are defined as byte-offsets from the iobase value. */ + +#define HDSPM_controlRegister 64 +#define HDSPM_interruptConfirmation 96 +#define HDSPM_control2Reg 256 /* not in specs ???????? */ +#define HDSPM_midiDataOut0 352 /* just believe in old code */ +#define HDSPM_midiDataOut1 356 + +/* DMA enable for 64 channels, only Bit 0 is relevant */ +#define HDSPM_outputEnableBase 512 /* 512-767 input DMA */ +#define HDSPM_inputEnableBase 768 /* 768-1023 output DMA */ + +/* 16 page addresses for each of the 64 channels DMA buffer in and out + (each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */ +#define HDSPM_pageAddressBufferOut 8192 +#define HDSPM_pageAddressBufferIn (HDSPM_pageAddressBufferOut+64*16*4) + +#define HDSPM_MADI_mixerBase 32768 /* 32768-65535 for 2x64x64 Fader */ + +#define HDSPM_MATRIX_MIXER_SIZE 8192 /* = 2*64*64 * 4 Byte => 32kB */ + +/* --- Read registers. --- + These are defined as byte-offsets from the iobase value */ +#define HDSPM_statusRegister 0 +#define HDSPM_statusRegister2 96 + +#define HDSPM_midiDataIn0 360 +#define HDSPM_midiDataIn1 364 + +/* status is data bytes in MIDI-FIFO (0-128) */ +#define HDSPM_midiStatusOut0 384 +#define HDSPM_midiStatusOut1 388 +#define HDSPM_midiStatusIn0 392 +#define HDSPM_midiStatusIn1 396 + + +/* the meters are regular i/o-mapped registers, but offset + considerably from the rest. the peak registers are reset + when read; the least-significant 4 bits are full-scale counters; + the actual peak value is in the most-significant 24 bits. +*/ +#define HDSPM_MADI_peakrmsbase 4096 /* 4096-8191 2x64x32Bit Meters */ + +/* --- Control Register bits --------- */ +#define HDSPM_Start (1<<0) /* start engine */ + +#define HDSPM_Latency0 (1<<1) /* buffer size = 2^n */ +#define HDSPM_Latency1 (1<<2) /* where n is defined */ +#define HDSPM_Latency2 (1<<3) /* by Latency{2,1,0} */ + +#define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Slave/Autosync */ + +#define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */ + +#define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ +#define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */ +#define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ +#define HDSPM_QuadSpeed (1<<31) /* quad speed bit, not implemented now */ + +#define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1, + 56channelMODE=0 */ + +#define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode, + 0=off, 1=on */ + +#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ +#define HDSPM_InputSelect1 (1<<15) /* should be 0 */ + +#define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */ +#define HDSPM_SyncRef1 (1<<17) /* should be 0 */ + +#define HDSPM_clr_tms (1<<19) /* clear track marker, do not use + AES additional bits in + lower 5 Audiodatabits ??? */ + +#define HDSPM_Midi0InterruptEnable (1<<22) +#define HDSPM_Midi1InterruptEnable (1<<23) + +#define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */ + + +/* --- bit helper defines */ +#define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) +#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1) +#define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) +#define HDSPM_InputOptical 0 +#define HDSPM_InputCoaxial (HDSPM_InputSelect0) +#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1) +#define HDSPM_SyncRef_Word 0 +#define HDSPM_SyncRef_MADI (HDSPM_SyncRef0) + +#define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */ +#define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */ + +#define HDSPM_Frequency32KHz HDSPM_Frequency0 +#define HDSPM_Frequency44_1KHz HDSPM_Frequency1 +#define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0) +#define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) +#define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) +#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0) + +/* --- for internal discrimination */ +#define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */ +#define HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ 1 +#define HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ 2 +#define HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ 3 +#define HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ 4 +#define HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ 5 +#define HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ 6 +#define HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ 7 +#define HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ 8 +#define HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ 9 + +/* Synccheck Status */ +#define HDSPM_SYNC_CHECK_NO_LOCK 0 +#define HDSPM_SYNC_CHECK_LOCK 1 +#define HDSPM_SYNC_CHECK_SYNC 2 + +/* AutoSync References - used by "autosync_ref" control switch */ +#define HDSPM_AUTOSYNC_FROM_WORD 0 +#define HDSPM_AUTOSYNC_FROM_MADI 1 +#define HDSPM_AUTOSYNC_FROM_NONE 2 + +/* Possible sources of MADI input */ +#define HDSPM_OPTICAL 0 /* optical */ +#define HDSPM_COAXIAL 1 /* BNC */ + +#define hdspm_encode_latency(x) (((x)<<1) & HDSPM_LatencyMask) +#define hdspm_decode_latency(x) (((x) & HDSPM_LatencyMask)>>1) + +#define hdspm_encode_in(x) (((x)&0x3)<<14) +#define hdspm_decode_in(x) (((x)>>14)&0x3) + +/* --- control2 register bits --- */ +#define HDSPM_TMS (1<<0) +#define HDSPM_TCK (1<<1) +#define HDSPM_TDI (1<<2) +#define HDSPM_JTAG (1<<3) +#define HDSPM_PWDN (1<<4) +#define HDSPM_PROGRAM (1<<5) +#define HDSPM_CONFIG_MODE_0 (1<<6) +#define HDSPM_CONFIG_MODE_1 (1<<7) +/*#define HDSPM_VERSION_BIT (1<<8) not defined any more*/ +#define HDSPM_BIGENDIAN_MODE (1<<9) +#define HDSPM_RD_MULTIPLE (1<<10) + +/* --- Status Register bits --- */ +#define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ +#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */ +#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */ +#define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ + +#define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ + /* since 64byte accurate last 6 bits + are not used */ + +#define HDSPM_madiSync (1<<18) /* MADI is in sync */ +#define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */ + +#define HDSPM_madiFreq0 (1<<22) /* system freq 0=error */ +#define HDSPM_madiFreq1 (1<<23) /* 1=32, 2=44.1 3=48 */ +#define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */ +#define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */ + +#define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with Interrupt */ +#define HDSPM_midi0IRQPending (1<<30) /* MIDI IRQ is pending */ +#define HDSPM_midi1IRQPending (1<<31) /* and aktiv */ + +/* --- status bit helpers */ +#define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2|HDSPM_madiFreq3) +#define HDSPM_madiFreq32 (HDSPM_madiFreq0) +#define HDSPM_madiFreq44_1 (HDSPM_madiFreq1) +#define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1) +#define HDSPM_madiFreq64 (HDSPM_madiFreq2) +#define HDSPM_madiFreq88_2 (HDSPM_madiFreq0|HDSPM_madiFreq2) +#define HDSPM_madiFreq96 (HDSPM_madiFreq1|HDSPM_madiFreq2) +#define HDSPM_madiFreq128 (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2) +#define HDSPM_madiFreq176_4 (HDSPM_madiFreq3) +#define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0) + +/* Status2 Register bits */ + +#define HDSPM_version0 (1<<0) /* not realy defined but I guess */ +#define HDSPM_version1 (1<<1) /* in former cards it was ??? */ +#define HDSPM_version2 (1<<2) + +#define HDSPM_wcLock (1<<3) /* Wordclock is detected and locked */ +#define HDSPM_wcSync (1<<4) /* Wordclock is in sync with systemclock */ + +#define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */ +#define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */ +#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, */ +/* missing Bit for 111=128, 1000=176.4, 1001=192 */ + +#define HDSPM_SelSyncRef0 (1<<8) /* Sync Source in slave mode */ +#define HDSPM_SelSyncRef1 (1<<9) /* 000=word, 001=MADI, */ +#define HDSPM_SelSyncRef2 (1<<10) /* 111=no valid signal */ + +#define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync) + +#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreq32 (HDSPM_wc_freq0) +#define HDSPM_wcFreq44_1 (HDSPM_wc_freq1) +#define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1) +#define HDSPM_wcFreq64 (HDSPM_wc_freq2) +#define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2) +#define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) + + +#define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) +#define HDSPM_SelSyncRef_WORD 0 +#define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) +#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) + +/* Mixer Values */ +#define UNITY_GAIN 32768 /* = 65536/2 */ +#define MINUS_INFINITY_GAIN 0 + +/* PCI info */ +#ifndef PCI_VENDOR_ID_XILINX +#define PCI_VENDOR_ID_XILINX 0x10ee +#endif +#ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP +#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 +#endif +#ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI +#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6 +#endif + + +/* Number of channels for different Speed Modes */ +#define MADI_SS_CHANNELS 64 +#define MADI_DS_CHANNELS 32 +#define MADI_QS_CHANNELS 16 + +/* the size of a substream (1 mono data stream) */ +#define HDSPM_CHANNEL_BUFFER_SAMPLES (16*1024) +#define HDSPM_CHANNEL_BUFFER_BYTES (4*HDSPM_CHANNEL_BUFFER_SAMPLES) + +/* the size of the area we need to allocate for DMA transfers. the + size is the same regardless of the number of channels, and + also the latency to use. + for one direction !!! +*/ +#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) +#define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) + +typedef struct _hdspm hdspm_t; +typedef struct _hdspm_midi hdspm_midi_t; + +struct _hdspm_midi { + hdspm_t *hdspm; + int id; + snd_rawmidi_t *rmidi; + snd_rawmidi_substream_t *input; + snd_rawmidi_substream_t *output; + char istimer; /* timer in use */ + struct timer_list timer; + spinlock_t lock; + int pending; +}; + +struct _hdspm { + spinlock_t lock; + snd_pcm_substream_t *capture_substream; /* only one playback */ + snd_pcm_substream_t *playback_substream; /* and/or capture stream */ + + char *card_name; /* for procinfo */ + unsigned short firmware_rev; /* dont know if relevant */ + + int precise_ptr; /* use precise pointers, to be tested */ + int monitor_outs; /* set up monitoring outs init flag */ + + u32 control_register; /* cached value */ + u32 control2_register; /* cached value */ + + hdspm_midi_t midi[2]; + struct tasklet_struct midi_tasklet; + + size_t period_bytes; + unsigned char ss_channels; /* channels of card in single speed */ + unsigned char ds_channels; /* Double Speed */ + unsigned char qs_channels; /* Quad Speed */ + + unsigned char *playback_buffer; /* suitably aligned address */ + unsigned char *capture_buffer; /* suitably aligned address */ + + pid_t capture_pid; /* process id which uses capture */ + pid_t playback_pid; /* process id which uses capture */ + int running; /* running status */ + + int last_external_sample_rate; /* samplerate mystic ... */ + int last_internal_sample_rate; + int system_sample_rate; + + char *channel_map; /* channel map for DS and Quadspeed */ + + int dev; /* Hardware vars... */ + int irq; + unsigned long port; + void __iomem *iobase; + + int irq_count; /* for debug */ + + snd_card_t *card; /* one card */ + snd_pcm_t *pcm; /* has one pcm */ + snd_hwdep_t *hwdep; /* and a hwdep for additional ioctl */ + struct pci_dev *pci; /* and an pci info */ + + /* Mixer vars */ + snd_kcontrol_t *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; /* fast alsa mixer */ + snd_kcontrol_t *input_mixer_ctls[HDSPM_MAX_CHANNELS]; /* but input to much, so not used */ + hdspm_mixer_t *mixer; /* full mixer accessable over mixer ioctl or hwdep-device */ + +}; + +/* These tables map the ALSA channels 1..N to the channels that we + need to use in order to find the relevant channel buffer. RME + refer to this kind of mapping as between "the ADAT channel and + the DMA channel." We index it using the logical audio channel, + and the value is the DMA channel (i.e. channel buffer number) + where the data for that channel can be read/written from/to. +*/ + +static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63 +}; + +static char channel_map_madi_ds[HDSPM_MAX_CHANNELS] = { + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 60, 62, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static char channel_map_madi_qs[HDSPM_MAX_CHANNELS] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60 + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; + + +static struct pci_device_id snd_hdspm_ids[] = { + { + .vendor = PCI_VENDOR_ID_XILINX, + .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + .driver_data = 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, snd_hdspm_ids); + +/* prototypes */ +static int __devinit snd_hdspm_create_alsa_devices(snd_card_t * card, + hdspm_t * hdspm); +static int __devinit snd_hdspm_create_pcm(snd_card_t * card, + hdspm_t * hdspm); + +static inline void snd_hdspm_initialize_midi_flush(hdspm_t * hdspm); +static int hdspm_update_simple_mixer_controls(hdspm_t * hdspm); +static int hdspm_autosync_ref(hdspm_t * hdspm); +static int snd_hdspm_set_defaults(hdspm_t * hdspm); +static void hdspm_set_sgbuf(hdspm_t * hdspm, struct snd_sg_buf *sgbuf, + unsigned int reg, int channels); + +/* Write/read to/from HDSPM with Adresses in Bytes + not words but only 32Bit writes are allowed */ + +static inline void hdspm_write(hdspm_t * hdspm, unsigned int reg, + unsigned int val) +{ + writel(val, hdspm->iobase + reg); +} + +static inline unsigned int hdspm_read(hdspm_t * hdspm, unsigned int reg) +{ + return readl(hdspm->iobase + reg); +} + +/* for each output channel (chan) I have an Input (in) and Playback (pb) Fader + mixer is write only on hardware so we have to cache him for read + each fader is a u32, but uses only the first 16 bit */ + +static inline int hdspm_read_in_gain(hdspm_t * hdspm, unsigned int chan, + unsigned int in) +{ + if (chan > HDSPM_MIXER_CHANNELS || in > HDSPM_MIXER_CHANNELS) + return 0; + + return hdspm->mixer->ch[chan].in[in]; +} + +static inline int hdspm_read_pb_gain(hdspm_t * hdspm, unsigned int chan, + unsigned int pb) +{ + if (chan > HDSPM_MIXER_CHANNELS || pb > HDSPM_MIXER_CHANNELS) + return 0; + return hdspm->mixer->ch[chan].pb[pb]; +} + +static inline int hdspm_write_in_gain(hdspm_t * hdspm, unsigned int chan, + unsigned int in, unsigned short data) +{ + if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) + return -1; + + hdspm_write(hdspm, + HDSPM_MADI_mixerBase + + ((in + 128 * chan) * sizeof(u32)), + (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF)); + return 0; +} + +static inline int hdspm_write_pb_gain(hdspm_t * hdspm, unsigned int chan, + unsigned int pb, unsigned short data) +{ + if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) + return -1; + + hdspm_write(hdspm, + HDSPM_MADI_mixerBase + + ((64 + pb + 128 * chan) * sizeof(u32)), + (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF)); + return 0; +} + + +/* enable DMA for specific channels, now available for DSP-MADI */ +static inline void snd_hdspm_enable_in(hdspm_t * hdspm, int i, int v) +{ + hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v); +} + +static inline void snd_hdspm_enable_out(hdspm_t * hdspm, int i, int v) +{ + hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v); +} + +/* check if same process is writing and reading */ +static inline int snd_hdspm_use_is_exclusive(hdspm_t * hdspm) +{ + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&hdspm->lock, flags); + if ((hdspm->playback_pid != hdspm->capture_pid) && + (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) { + ret = 0; + } + spin_unlock_irqrestore(&hdspm->lock, flags); + return ret; +} + +/* check for external sample rate */ +static inline int hdspm_external_sample_rate(hdspm_t * hdspm) +{ + unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); + unsigned int rate_bits; + int rate = 0; + + /* if wordclock has synced freq and wordclock is valid */ + if ((status2 & HDSPM_wcLock) != 0 && + (status & HDSPM_SelSyncRef0) == 0) { + + rate_bits = status2 & HDSPM_wcFreqMask; + + switch (rate_bits) { + case HDSPM_wcFreq32: + rate = 32000; + break; + case HDSPM_wcFreq44_1: + rate = 44100; + break; + case HDSPM_wcFreq48: + rate = 48000; + break; + case HDSPM_wcFreq64: + rate = 64000; + break; + case HDSPM_wcFreq88_2: + rate = 88200; + break; + case HDSPM_wcFreq96: + rate = 96000; + break; + /* Quadspeed Bit missing ???? */ + default: + rate = 0; + break; + } + } + + /* if rate detected and Syncref is Word than have it, word has priority to MADI */ + if (rate != 0 + && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) + return rate; + + /* maby a madi input (which is taken if sel sync is madi) */ + if (status & HDSPM_madiLock) { + rate_bits = status & HDSPM_madiFreqMask; + + switch (rate_bits) { + case HDSPM_madiFreq32: + rate = 32000; + break; + case HDSPM_madiFreq44_1: + rate = 44100; + break; + case HDSPM_madiFreq48: + rate = 48000; + break; + case HDSPM_madiFreq64: + rate = 64000; + break; + case HDSPM_madiFreq88_2: + rate = 88200; + break; + case HDSPM_madiFreq96: + rate = 96000; + break; + case HDSPM_madiFreq128: + rate = 128000; + break; + case HDSPM_madiFreq176_4: + rate = 176400; + break; + case HDSPM_madiFreq192: + rate = 192000; + break; + default: + rate = 0; + break; + } + } + return rate; +} + +/* Latency function */ +static inline void hdspm_compute_period_size(hdspm_t * hdspm) +{ + hdspm->period_bytes = + 1 << ((hdspm_decode_latency(hdspm->control_register) + 8)); +} + +static snd_pcm_uframes_t hdspm_hw_pointer(hdspm_t * hdspm) +{ + int position; + + position = hdspm_read(hdspm, HDSPM_statusRegister); + + if (!hdspm->precise_ptr) { + return (position & HDSPM_BufferID) ? (hdspm->period_bytes / + 4) : 0; + } + + /* hwpointer comes in bytes and is 64Bytes accurate (by docu since PCI Burst) + i have experimented that it is at most 64 Byte to much for playing + so substraction of 64 byte should be ok for ALSA, but use it only + for application where you know what you do since if you come to + near with record pointer it can be a disaster */ + + position &= HDSPM_BufferPositionMask; + position = ((position - 64) % (2 * hdspm->period_bytes)) / 4; + + return position; +} + + +static inline void hdspm_start_audio(hdspm_t * s) +{ + s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start); + hdspm_write(s, HDSPM_controlRegister, s->control_register); +} + +static inline void hdspm_stop_audio(hdspm_t * s) +{ + s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable); + hdspm_write(s, HDSPM_controlRegister, s->control_register); +} + +/* should I silence all or only opened ones ? doit all for first even is 4MB*/ +static inline void hdspm_silence_playback(hdspm_t * hdspm) +{ + int i; + int n = hdspm->period_bytes; + void *buf = hdspm->playback_buffer; + + snd_assert(buf != NULL, return); + + for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { + memset(buf, 0, n); + buf += HDSPM_CHANNEL_BUFFER_BYTES; + } +} + +static int hdspm_set_interrupt_interval(hdspm_t * s, unsigned int frames) +{ + int n; + + spin_lock_irq(&s->lock); + + frames >>= 7; + n = 0; + while (frames) { + n++; + frames >>= 1; + } + s->control_register &= ~HDSPM_LatencyMask; + s->control_register |= hdspm_encode_latency(n); + + hdspm_write(s, HDSPM_controlRegister, s->control_register); + + hdspm_compute_period_size(s); + + spin_unlock_irq(&s->lock); + + return 0; +} + + +/* dummy set rate lets see what happens */ +static int hdspm_set_rate(hdspm_t * hdspm, int rate, int called_internally) +{ + int reject_if_open = 0; + int current_rate; + int rate_bits; + int not_set = 0; + + /* ASSUMPTION: hdspm->lock is either set, or there is no need for + it (e.g. during module initialization). + */ + + if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { + + /* SLAVE --- */ + if (called_internally) { + + /* request from ctl or card initialization + just make a warning an remember setting + for future master mode switching */ + + snd_printk + (KERN_WARNING "HDSPM: Warning: device is not running as a clock master.\n"); + not_set = 1; + } else { + + /* hw_param request while in AutoSync mode */ + int external_freq = + hdspm_external_sample_rate(hdspm); + + if ((hdspm_autosync_ref(hdspm) == + HDSPM_AUTOSYNC_FROM_NONE)) { + + snd_printk(KERN_WARNING "HDSPM: Detected no Externel Sync \n"); + not_set = 1; + + } else if (rate != external_freq) { + + snd_printk + (KERN_WARNING "HDSPM: Warning: No AutoSync source for requested rate\n"); + not_set = 1; + } + } + } + + current_rate = hdspm->system_sample_rate; + + /* Changing between Singe, Double and Quad speed is not + allowed if any substreams are open. This is because such a change + causes a shift in the location of the DMA buffers and a reduction + in the number of available buffers. + + Note that a similar but essentially insoluble problem exists for + externally-driven rate changes. All we can do is to flag rate + changes in the read/write routines. + */ + + switch (rate) { + case 32000: + if (current_rate > 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency32KHz; + break; + case 44100: + if (current_rate > 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency44_1KHz; + break; + case 48000: + if (current_rate > 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency48KHz; + break; + case 64000: + if (current_rate <= 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency64KHz; + break; + case 88200: + if (current_rate <= 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency88_2KHz; + break; + case 96000: + if (current_rate <= 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency96KHz; + break; + default: + return -EINVAL; + } + + if (reject_if_open + && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { + snd_printk + (KERN_ERR "HDSPM: cannot change between single- and double-speed mode (capture PID = %d, playback PID = %d)\n", + hdspm->capture_pid, hdspm->playback_pid); + return -EBUSY; + } + + hdspm->control_register &= ~HDSPM_FrequencyMask; + hdspm->control_register |= rate_bits; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + if (rate > 64000) + hdspm->channel_map = channel_map_madi_qs; + else if (rate > 48000) + hdspm->channel_map = channel_map_madi_ds; + else + hdspm->channel_map = channel_map_madi_ss; + + hdspm->system_sample_rate = rate; + + if (not_set != 0) + return -1; + + return 0; +} + +/* mainly for init to 0 on load */ +static void all_in_all_mixer(hdspm_t * hdspm, int sgain) +{ + int i, j; + unsigned int gain = + (sgain > UNITY_GAIN) ? UNITY_GAIN : (sgain < 0) ? 0 : sgain; + + for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) + for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) { + hdspm_write_in_gain(hdspm, i, j, gain); + hdspm_write_pb_gain(hdspm, i, j, gain); + } +} + +/*---------------------------------------------------------------------------- + MIDI + ----------------------------------------------------------------------------*/ + +static inline unsigned char snd_hdspm_midi_read_byte (hdspm_t *hdspm, int id) +{ + /* the hardware already does the relevant bit-mask with 0xff */ + if (id) + return hdspm_read(hdspm, HDSPM_midiDataIn1); + else + return hdspm_read(hdspm, HDSPM_midiDataIn0); +} + +static inline void snd_hdspm_midi_write_byte (hdspm_t *hdspm, int id, int val) +{ + /* the hardware already does the relevant bit-mask with 0xff */ + if (id) + return hdspm_write(hdspm, HDSPM_midiDataOut1, val); + else + return hdspm_write(hdspm, HDSPM_midiDataOut0, val); +} + +static inline int snd_hdspm_midi_input_available (hdspm_t *hdspm, int id) +{ + if (id) + return (hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff); + else + return (hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff); +} + +static inline int snd_hdspm_midi_output_possible (hdspm_t *hdspm, int id) +{ + int fifo_bytes_used; + + if (id) + fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xff; + else + fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xff; + + if (fifo_bytes_used < 128) + return 128 - fifo_bytes_used; + else + return 0; +} + +static inline void snd_hdspm_flush_midi_input (hdspm_t *hdspm, int id) +{ + while (snd_hdspm_midi_input_available (hdspm, id)) + snd_hdspm_midi_read_byte (hdspm, id); +} + +static int snd_hdspm_midi_output_write (hdspm_midi_t *hmidi) +{ + unsigned long flags; + int n_pending; + int to_write; + int i; + unsigned char buf[128]; + + /* Output is not interrupt driven */ + + spin_lock_irqsave (&hmidi->lock, flags); + if (hmidi->output) { + if (!snd_rawmidi_transmit_empty (hmidi->output)) { + if ((n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, hmidi->id)) > 0) { + if (n_pending > (int)sizeof (buf)) + n_pending = sizeof (buf); + + if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) { + for (i = 0; i < to_write; ++i) + snd_hdspm_midi_write_byte (hmidi->hdspm, hmidi->id, buf[i]); + } + } + } + } + spin_unlock_irqrestore (&hmidi->lock, flags); + return 0; +} + +static int snd_hdspm_midi_input_read (hdspm_midi_t *hmidi) +{ + unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */ + unsigned long flags; + int n_pending; + int i; + + spin_lock_irqsave (&hmidi->lock, flags); + if ((n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id)) > 0) { + if (hmidi->input) { + if (n_pending > (int)sizeof (buf)) { + n_pending = sizeof (buf); + } + for (i = 0; i < n_pending; ++i) { + buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); + } + if (n_pending) { + snd_rawmidi_receive (hmidi->input, buf, n_pending); + } + } else { + /* flush the MIDI input FIFO */ + while (n_pending--) { + snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); + } + } + } + hmidi->pending = 0; + if (hmidi->id) { + hmidi->hdspm->control_register |= HDSPM_Midi1InterruptEnable; + } else { + hmidi->hdspm->control_register |= HDSPM_Midi0InterruptEnable; + } + hdspm_write(hmidi->hdspm, HDSPM_controlRegister, hmidi->hdspm->control_register); + spin_unlock_irqrestore (&hmidi->lock, flags); + return snd_hdspm_midi_output_write (hmidi); +} + +static void snd_hdspm_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) +{ + hdspm_t *hdspm; + hdspm_midi_t *hmidi; + unsigned long flags; + u32 ie; + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + hdspm = hmidi->hdspm; + ie = hmidi->id ? HDSPM_Midi1InterruptEnable : HDSPM_Midi0InterruptEnable; + spin_lock_irqsave (&hdspm->lock, flags); + if (up) { + if (!(hdspm->control_register & ie)) { + snd_hdspm_flush_midi_input (hdspm, hmidi->id); + hdspm->control_register |= ie; + } + } else { + hdspm->control_register &= ~ie; + } + + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + spin_unlock_irqrestore (&hdspm->lock, flags); +} + +static void snd_hdspm_midi_output_timer(unsigned long data) +{ + hdspm_midi_t *hmidi = (hdspm_midi_t *) data; + unsigned long flags; + + snd_hdspm_midi_output_write(hmidi); + spin_lock_irqsave (&hmidi->lock, flags); + + /* this does not bump hmidi->istimer, because the + kernel automatically removed the timer when it + expired, and we are now adding it back, thus + leaving istimer wherever it was set before. + */ + + if (hmidi->istimer) { + hmidi->timer.expires = 1 + jiffies; + add_timer(&hmidi->timer); + } + + spin_unlock_irqrestore (&hmidi->lock, flags); +} + +static void snd_hdspm_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) +{ + hdspm_midi_t *hmidi; + unsigned long flags; + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + spin_lock_irqsave (&hmidi->lock, flags); + if (up) { + if (!hmidi->istimer) { + init_timer(&hmidi->timer); + hmidi->timer.function = snd_hdspm_midi_output_timer; + hmidi->timer.data = (unsigned long) hmidi; + hmidi->timer.expires = 1 + jiffies; + add_timer(&hmidi->timer); + hmidi->istimer++; + } + } else { + if (hmidi->istimer && --hmidi->istimer <= 0) { + del_timer (&hmidi->timer); + } + } + spin_unlock_irqrestore (&hmidi->lock, flags); + if (up) + snd_hdspm_midi_output_write(hmidi); +} + +static int snd_hdspm_midi_input_open(snd_rawmidi_substream_t * substream) +{ + hdspm_midi_t *hmidi; + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + spin_lock_irq (&hmidi->lock); + snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); + hmidi->input = substream; + spin_unlock_irq (&hmidi->lock); + + return 0; +} + +static int snd_hdspm_midi_output_open(snd_rawmidi_substream_t * substream) +{ + hdspm_midi_t *hmidi; + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + spin_lock_irq (&hmidi->lock); + hmidi->output = substream; + spin_unlock_irq (&hmidi->lock); + + return 0; +} + +static int snd_hdspm_midi_input_close(snd_rawmidi_substream_t * substream) +{ + hdspm_midi_t *hmidi; + + snd_hdspm_midi_input_trigger (substream, 0); + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + spin_lock_irq (&hmidi->lock); + hmidi->input = NULL; + spin_unlock_irq (&hmidi->lock); + + return 0; +} + +static int snd_hdspm_midi_output_close(snd_rawmidi_substream_t * substream) +{ + hdspm_midi_t *hmidi; + + snd_hdspm_midi_output_trigger (substream, 0); + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + spin_lock_irq (&hmidi->lock); + hmidi->output = NULL; + spin_unlock_irq (&hmidi->lock); + + return 0; +} + +snd_rawmidi_ops_t snd_hdspm_midi_output = +{ + .open = snd_hdspm_midi_output_open, + .close = snd_hdspm_midi_output_close, + .trigger = snd_hdspm_midi_output_trigger, +}; + +snd_rawmidi_ops_t snd_hdspm_midi_input = +{ + .open = snd_hdspm_midi_input_open, + .close = snd_hdspm_midi_input_close, + .trigger = snd_hdspm_midi_input_trigger, +}; + +static int __devinit snd_hdspm_create_midi (snd_card_t *card, hdspm_t *hdspm, int id) +{ + int err; + char buf[32]; + + hdspm->midi[id].id = id; + hdspm->midi[id].rmidi = NULL; + hdspm->midi[id].input = NULL; + hdspm->midi[id].output = NULL; + hdspm->midi[id].hdspm = hdspm; + hdspm->midi[id].istimer = 0; + hdspm->midi[id].pending = 0; + spin_lock_init (&hdspm->midi[id].lock); + + sprintf (buf, "%s MIDI %d", card->shortname, id+1); + if ((err = snd_rawmidi_new (card, buf, id, 1, 1, &hdspm->midi[id].rmidi)) < 0) + return err; + + sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); + hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; + + snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdspm_midi_output); + snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_hdspm_midi_input); + + hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + + return 0; +} + + +static void hdspm_midi_tasklet(unsigned long arg) +{ + hdspm_t *hdspm = (hdspm_t *)arg; + + if (hdspm->midi[0].pending) + snd_hdspm_midi_input_read (&hdspm->midi[0]); + if (hdspm->midi[1].pending) + snd_hdspm_midi_input_read (&hdspm->midi[1]); +} + + +/*----------------------------------------------------------------------------- + Status Interface + ----------------------------------------------------------------------------*/ + +/* get the system sample rate which is set */ + +#define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdspm_info_system_sample_rate, \ + .get = snd_hdspm_get_system_sample_rate \ +} + +static int snd_hdspm_info_system_sample_rate(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + return 0; +} + +static int snd_hdspm_get_system_sample_rate(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * + ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm->system_sample_rate; + return 0; +} + +#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdspm_info_autosync_sample_rate, \ + .get = snd_hdspm_get_autosync_sample_rate \ +} + +static int snd_hdspm_info_autosync_sample_rate(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "32000", "44100", "48000", + "64000", "88200", "96000", + "128000", "176400", "192000", + "None" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 10; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdspm_get_autosync_sample_rate(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * + ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + switch (hdspm_external_sample_rate(hdspm)) { + case 32000: + ucontrol->value.enumerated.item[0] = 0; + break; + case 44100: + ucontrol->value.enumerated.item[0] = 1; + break; + case 48000: + ucontrol->value.enumerated.item[0] = 2; + break; + case 64000: + ucontrol->value.enumerated.item[0] = 3; + break; + case 88200: + ucontrol->value.enumerated.item[0] = 4; + break; + case 96000: + ucontrol->value.enumerated.item[0] = 5; + break; + case 128000: + ucontrol->value.enumerated.item[0] = 6; + break; + case 176400: + ucontrol->value.enumerated.item[0] = 7; + break; + case 192000: + ucontrol->value.enumerated.item[0] = 8; + break; + + default: + ucontrol->value.enumerated.item[0] = 9; + } + return 0; +} + +#define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdspm_info_system_clock_mode, \ + .get = snd_hdspm_get_system_clock_mode, \ +} + + + +static int hdspm_system_clock_mode(hdspm_t * hdspm) +{ + /* Always reflect the hardware info, rme is never wrong !!!! */ + + if (hdspm->control_register & HDSPM_ClockModeMaster) + return 0; + return 1; +} + +static int snd_hdspm_info_system_clock_mode(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "Master", "Slave" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdspm_get_system_clock_mode(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = + hdspm_system_clock_mode(hdspm); + return 0; +} + +#define HDSPM_CLOCK_SOURCE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_clock_source, \ + .get = snd_hdspm_get_clock_source, \ + .put = snd_hdspm_put_clock_source \ +} + +static int hdspm_clock_source(hdspm_t * hdspm) +{ + if (hdspm->control_register & HDSPM_ClockModeMaster) { + switch (hdspm->system_sample_rate) { + case 32000: + return 1; + case 44100: + return 2; + case 48000: + return 3; + case 64000: + return 4; + case 88200: + return 5; + case 96000: + return 6; + case 128000: + return 7; + case 176400: + return 8; + case 192000: + return 9; + default: + return 3; + } + } else { + return 0; + } +} + +static int hdspm_set_clock_source(hdspm_t * hdspm, int mode) +{ + int rate; + switch (mode) { + + case HDSPM_CLOCK_SOURCE_AUTOSYNC: + if (hdspm_external_sample_rate(hdspm) != 0) { + hdspm->control_register &= ~HDSPM_ClockModeMaster; + hdspm_write(hdspm, HDSPM_controlRegister, + hdspm->control_register); + return 0; + } + return -1; + case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ: + rate = 32000; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ: + rate = 44100; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ: + rate = 48000; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ: + rate = 64000; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ: + rate = 88200; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ: + rate = 96000; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ: + rate = 128000; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ: + rate = 176400; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ: + rate = 192000; + break; + + default: + rate = 44100; + } + hdspm->control_register |= HDSPM_ClockModeMaster; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + hdspm_set_rate(hdspm, rate, 1); + return 0; +} + +static int snd_hdspm_info_clock_source(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "AutoSync", + "Internal 32.0 kHz", "Internal 44.1 kHz", + "Internal 48.0 kHz", + "Internal 64.0 kHz", "Internal 88.2 kHz", + "Internal 96.0 kHz", + "Internal 128.0 kHz", "Internal 176.4 kHz", + "Internal 192.0 kHz" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 10; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int snd_hdspm_get_clock_source(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm_clock_source(hdspm); + return 0; +} + +static int snd_hdspm_put_clock_source(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.enumerated.item[0]; + if (val < 0) + val = 0; + if (val > 6) + val = 6; + spin_lock_irq(&hdspm->lock); + if (val != hdspm_clock_source(hdspm)) + change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0; + else + change = 0; + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_PREF_SYNC_REF(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_pref_sync_ref, \ + .get = snd_hdspm_get_pref_sync_ref, \ + .put = snd_hdspm_put_pref_sync_ref \ +} + +static int hdspm_pref_sync_ref(hdspm_t * hdspm) +{ + /* Notice that this looks at the requested sync source, + not the one actually in use. + */ + switch (hdspm->control_register & HDSPM_SyncRefMask) { + case HDSPM_SyncRef_Word: + return HDSPM_SYNC_FROM_WORD; + case HDSPM_SyncRef_MADI: + return HDSPM_SYNC_FROM_MADI; + } + + return HDSPM_SYNC_FROM_WORD; +} + +static int hdspm_set_pref_sync_ref(hdspm_t * hdspm, int pref) +{ + hdspm->control_register &= ~HDSPM_SyncRefMask; + + switch (pref) { + case HDSPM_SYNC_FROM_MADI: + hdspm->control_register |= HDSPM_SyncRef_MADI; + break; + case HDSPM_SYNC_FROM_WORD: + hdspm->control_register |= HDSPM_SyncRef_Word; + break; + default: + return -1; + } + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + return 0; +} + +static int snd_hdspm_info_pref_sync_ref(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "Word", "MADI" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdspm_get_pref_sync_ref(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm); + return 0; +} + +static int snd_hdspm_put_pref_sync_ref(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change, max; + unsigned int val; + + max = 2; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + + val = ucontrol->value.enumerated.item[0] % max; + + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_pref_sync_ref(hdspm); + hdspm_set_pref_sync_ref(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_AUTOSYNC_REF(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdspm_info_autosync_ref, \ + .get = snd_hdspm_get_autosync_ref, \ +} + +static int hdspm_autosync_ref(hdspm_t * hdspm) +{ + /* This looks at the autosync selected sync reference */ + unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + + switch (status2 & HDSPM_SelSyncRefMask) { + + case HDSPM_SelSyncRef_WORD: + return HDSPM_AUTOSYNC_FROM_WORD; + + case HDSPM_SelSyncRef_MADI: + return HDSPM_AUTOSYNC_FROM_MADI; + + case HDSPM_SelSyncRef_NVALID: + return HDSPM_AUTOSYNC_FROM_NONE; + + default: + return 0; + } + + return 0; +} + +static int snd_hdspm_info_autosync_ref(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "WordClock", "MADI", "None" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdspm_get_autosync_ref(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm); + return 0; +} + +#define HDSPM_LINE_OUT(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_line_out, \ + .get = snd_hdspm_get_line_out, \ + .put = snd_hdspm_put_line_out \ +} + +static int hdspm_line_out(hdspm_t * hdspm) +{ + return (hdspm->control_register & HDSPM_LineOut) ? 1 : 0; +} + + +static int hdspm_set_line_output(hdspm_t * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_LineOut; + else + hdspm->control_register &= ~HDSPM_LineOut; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_line_out(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_line_out(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = hdspm_line_out(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_line_out(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_line_out(hdspm); + hdspm_set_line_output(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_TX_64(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_tx_64, \ + .get = snd_hdspm_get_tx_64, \ + .put = snd_hdspm_put_tx_64 \ +} + +static int hdspm_tx_64(hdspm_t * hdspm) +{ + return (hdspm->control_register & HDSPM_TX_64ch) ? 1 : 0; +} + +static int hdspm_set_tx_64(hdspm_t * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_TX_64ch; + else + hdspm->control_register &= ~HDSPM_TX_64ch; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_tx_64(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_tx_64(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = hdspm_tx_64(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_tx_64(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_tx_64(hdspm); + hdspm_set_tx_64(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_C_TMS(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_c_tms, \ + .get = snd_hdspm_get_c_tms, \ + .put = snd_hdspm_put_c_tms \ +} + +static int hdspm_c_tms(hdspm_t * hdspm) +{ + return (hdspm->control_register & HDSPM_clr_tms) ? 1 : 0; +} + +static int hdspm_set_c_tms(hdspm_t * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_clr_tms; + else + hdspm->control_register &= ~HDSPM_clr_tms; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_c_tms(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_c_tms(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = hdspm_c_tms(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_c_tms(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_c_tms(hdspm); + hdspm_set_c_tms(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_SAFE_MODE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_safe_mode, \ + .get = snd_hdspm_get_safe_mode, \ + .put = snd_hdspm_put_safe_mode \ +} + +static int hdspm_safe_mode(hdspm_t * hdspm) +{ + return (hdspm->control_register & HDSPM_AutoInp) ? 1 : 0; +} + +static int hdspm_set_safe_mode(hdspm_t * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_AutoInp; + else + hdspm->control_register &= ~HDSPM_AutoInp; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_safe_mode(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_safe_mode(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = hdspm_safe_mode(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_safe_mode(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_safe_mode(hdspm); + hdspm_set_safe_mode(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_INPUT_SELECT(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_input_select, \ + .get = snd_hdspm_get_input_select, \ + .put = snd_hdspm_put_input_select \ +} + +static int hdspm_input_select(hdspm_t * hdspm) +{ + return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0; +} + +static int hdspm_set_input_select(hdspm_t * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_InputSelect0; + else + hdspm->control_register &= ~HDSPM_InputSelect0; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_input_select(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "optical", "coaxial" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int snd_hdspm_get_input_select(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_input_select(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_input_select(hdspm); + hdspm_set_input_select(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +/* Simple Mixer + deprecated since to much faders ??? + MIXER interface says output (source, destination, value) + where source > MAX_channels are playback channels + on MADICARD + - playback mixer matrix: [channelout+64] [output] [value] + - input(thru) mixer matrix: [channelin] [output] [value] + (better do 2 kontrols for seperation ?) +*/ + +#define HDSPM_MIXER(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_mixer, \ + .get = snd_hdspm_get_mixer, \ + .put = snd_hdspm_put_mixer \ +} + +static int snd_hdspm_info_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 3; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 65535; + uinfo->value.integer.step = 1; + return 0; +} + +static int snd_hdspm_get_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int source; + int destination; + + source = ucontrol->value.integer.value[0]; + if (source < 0) + source = 0; + else if (source >= 2 * HDSPM_MAX_CHANNELS) + source = 2 * HDSPM_MAX_CHANNELS - 1; + + destination = ucontrol->value.integer.value[1]; + if (destination < 0) + destination = 0; + else if (destination >= HDSPM_MAX_CHANNELS) + destination = HDSPM_MAX_CHANNELS - 1; + + spin_lock_irq(&hdspm->lock); + if (source >= HDSPM_MAX_CHANNELS) + ucontrol->value.integer.value[2] = + hdspm_read_pb_gain(hdspm, destination, + source - HDSPM_MAX_CHANNELS); + else + ucontrol->value.integer.value[2] = + hdspm_read_in_gain(hdspm, destination, source); + + spin_unlock_irq(&hdspm->lock); + + return 0; +} + +static int snd_hdspm_put_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + int source; + int destination; + int gain; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + + source = ucontrol->value.integer.value[0]; + destination = ucontrol->value.integer.value[1]; + + if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS) + return -1; + if (destination < 0 || destination >= HDSPM_MAX_CHANNELS) + return -1; + + gain = ucontrol->value.integer.value[2]; + + spin_lock_irq(&hdspm->lock); + + if (source >= HDSPM_MAX_CHANNELS) + change = gain != hdspm_read_pb_gain(hdspm, destination, + source - + HDSPM_MAX_CHANNELS); + else + change = + gain != hdspm_read_in_gain(hdspm, destination, source); + + if (change) { + if (source >= HDSPM_MAX_CHANNELS) + hdspm_write_pb_gain(hdspm, destination, + source - HDSPM_MAX_CHANNELS, + gain); + else + hdspm_write_in_gain(hdspm, destination, source, + gain); + } + spin_unlock_irq(&hdspm->lock); + + return change; +} + +/* The simple mixer control(s) provide gain control for the + basic 1:1 mappings of playback streams to output + streams. +*/ + +#define HDSPM_PLAYBACK_MIXER \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_playback_mixer, \ + .get = snd_hdspm_get_playback_mixer, \ + .put = snd_hdspm_put_playback_mixer \ +} + +static int snd_hdspm_info_playback_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 65536; + uinfo->value.integer.step = 1; + return 0; +} + +static int snd_hdspm_get_playback_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int channel; + int mapped_channel; + + channel = ucontrol->id.index - 1; + + snd_assert(channel >= 0 + || channel < HDSPM_MAX_CHANNELS, return -EINVAL); + + if ((mapped_channel = hdspm->channel_map[channel]) < 0) + return -EINVAL; + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = + hdspm_read_pb_gain(hdspm, mapped_channel, mapped_channel); + spin_unlock_irq(&hdspm->lock); + + /* snd_printdd("get pb mixer index %d, channel %d, mapped_channel %d, value %d\n", + ucontrol->id.index, channel, mapped_channel, ucontrol->value.integer.value[0]); + */ + + return 0; +} + +static int snd_hdspm_put_playback_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + int channel; + int mapped_channel; + int gain; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + + channel = ucontrol->id.index - 1; + + snd_assert(channel >= 0 + || channel < HDSPM_MAX_CHANNELS, return -EINVAL); + + if ((mapped_channel = hdspm->channel_map[channel]) < 0) + return -EINVAL; + + gain = ucontrol->value.integer.value[0]; + + spin_lock_irq(&hdspm->lock); + change = + gain != hdspm_read_pb_gain(hdspm, mapped_channel, + mapped_channel); + if (change) + hdspm_write_pb_gain(hdspm, mapped_channel, mapped_channel, + gain); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_WC_SYNC_CHECK(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_sync_check, \ + .get = snd_hdspm_get_wc_sync_check \ +} + +static int snd_hdspm_info_sync_check(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "No Lock", "Lock", "Sync" }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int hdspm_wc_sync_check(hdspm_t * hdspm) +{ + int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + if (status2 & HDSPM_wcLock) { + if (status2 & HDSPM_wcSync) + return 2; + else + return 1; + } + return 0; +} + +static int snd_hdspm_get_wc_sync_check(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm_wc_sync_check(hdspm); + return 0; +} + + +#define HDSPM_MADI_SYNC_CHECK(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_sync_check, \ + .get = snd_hdspm_get_madisync_sync_check \ +} + +static int hdspm_madisync_sync_check(hdspm_t * hdspm) +{ + int status = hdspm_read(hdspm, HDSPM_statusRegister); + if (status & HDSPM_madiLock) { + if (status & HDSPM_madiSync) + return 2; + else + return 1; + } + return 0; +} + +static int snd_hdspm_get_madisync_sync_check(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * + ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = + hdspm_madisync_sync_check(hdspm); + return 0; +} + + + + +static snd_kcontrol_new_t snd_hdspm_controls[] = { + + HDSPM_MIXER("Mixer", 0), +/* 'Sample Clock Source' complies with the alsa control naming scheme */ + HDSPM_CLOCK_SOURCE("Sample Clock Source", 0), + + HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), + HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), + HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), + HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), +/* 'External Rate' complies with the alsa control naming scheme */ + HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), + HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0), + HDSPM_MADI_SYNC_CHECK("MADI Sync Lock Status", 0), + HDSPM_LINE_OUT("Line Out", 0), + HDSPM_TX_64("TX 64 channels mode", 0), + HDSPM_C_TMS("Clear Track Marker", 0), + HDSPM_SAFE_MODE("Safe Mode", 0), + HDSPM_INPUT_SELECT("Input Select", 0), +}; + +static snd_kcontrol_new_t snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER; + + +static int hdspm_update_simple_mixer_controls(hdspm_t * hdspm) +{ + int i; + + for (i = hdspm->ds_channels; i < hdspm->ss_channels; ++i) { + if (hdspm->system_sample_rate > 48000) { + hdspm->playback_mixer_ctls[i]->vd[0].access = + SNDRV_CTL_ELEM_ACCESS_INACTIVE | + SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE; + } else { + hdspm->playback_mixer_ctls[i]->vd[0].access = + SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE; + } + snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE | + SNDRV_CTL_EVENT_MASK_INFO, + &hdspm->playback_mixer_ctls[i]->id); + } + + return 0; +} + + +static int snd_hdspm_create_controls(snd_card_t * card, hdspm_t * hdspm) +{ + unsigned int idx, limit; + int err; + snd_kcontrol_t *kctl; + + /* add control list first */ + + for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls); idx++) { + if ((err = + snd_ctl_add(card, kctl = + snd_ctl_new1(&snd_hdspm_controls[idx], + hdspm))) < 0) { + return err; + } + } + + /* Channel playback mixer as default control + Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats to big for any alsamixer + they are accesible via special IOCTL on hwdep + and the mixer 2dimensional mixer control */ + + snd_hdspm_playback_mixer.name = "Chn"; + limit = HDSPM_MAX_CHANNELS; + + /* The index values are one greater than the channel ID so that alsamixer + will display them correctly. We want to use the index for fast lookup + of the relevant channel, but if we use it at all, most ALSA software + does the wrong thing with it ... + */ + + for (idx = 0; idx < limit; ++idx) { + snd_hdspm_playback_mixer.index = idx + 1; + if ((err = snd_ctl_add(card, + kctl = + snd_ctl_new1 + (&snd_hdspm_playback_mixer, + hdspm)))) { + return err; + } + hdspm->playback_mixer_ctls[idx] = kctl; + } + + return 0; +} + +/*------------------------------------------------------------ + /proc interface + ------------------------------------------------------------*/ + +static void +snd_hdspm_proc_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer) +{ + hdspm_t *hdspm = (hdspm_t *) entry->private_data; + unsigned int status; + unsigned int status2; + char *pref_sync_ref; + char *autosync_ref; + char *system_clock_mode; + char *clock_source; + char *insel; + char *syncref; + int x, x2; + + status = hdspm_read(hdspm, HDSPM_statusRegister); + status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + + snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", + hdspm->card_name, hdspm->card->number + 1, + hdspm->firmware_rev, + (status2 & HDSPM_version0) | + (status2 & HDSPM_version1) | (status2 & + HDSPM_version2)); + + snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", + hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); + + snd_iprintf(buffer, "--- System ---\n"); + + snd_iprintf(buffer, + "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", + status & HDSPM_audioIRQPending, + (status & HDSPM_midi0IRQPending) ? 1 : 0, + (status & HDSPM_midi1IRQPending) ? 1 : 0, + hdspm->irq_count); + snd_iprintf(buffer, + "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n", + ((status & HDSPM_BufferID) ? 1 : 0), + (status & HDSPM_BufferPositionMask), + (status & HDSPM_BufferPositionMask) % (2 * + (int)hdspm-> + period_bytes), + ((status & HDSPM_BufferPositionMask) - + 64) % (2 * (int)hdspm->period_bytes), + (long) hdspm_hw_pointer(hdspm) * 4); + + snd_iprintf(buffer, + "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", + hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); + snd_iprintf(buffer, + "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x\n", + hdspm->control_register, hdspm->control2_register, + status, status2); + + snd_iprintf(buffer, "--- Settings ---\n"); + + x = 1 << (6 + + hdspm_decode_latency(hdspm-> + control_register & + HDSPM_LatencyMask)); + + snd_iprintf(buffer, + "Size (Latency): %d samples (2 periods of %lu bytes)\n", + x, (unsigned long) hdspm->period_bytes); + + snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n", + (hdspm-> + control_register & HDSPM_LineOut) ? "on " : "off", + (hdspm->precise_ptr) ? "on" : "off"); + + switch (hdspm->control_register & HDSPM_InputMask) { + case HDSPM_InputOptical: + insel = "Optical"; + break; + case HDSPM_InputCoaxial: + insel = "Coaxial"; + break; + default: + insel = "Unkown"; + } + + switch (hdspm->control_register & HDSPM_SyncRefMask) { + case HDSPM_SyncRef_Word: + syncref = "WordClock"; + break; + case HDSPM_SyncRef_MADI: + syncref = "MADI"; + break; + default: + syncref = "Unkown"; + } + snd_iprintf(buffer, "Inputsel = %s, SyncRef = %s\n", insel, + syncref); + + snd_iprintf(buffer, + "ClearTrackMarker = %s, Transmit in %s Channel Mode, Auto Input %s\n", + (hdspm-> + control_register & HDSPM_clr_tms) ? "on" : "off", + (hdspm-> + control_register & HDSPM_TX_64ch) ? "64" : "56", + (hdspm-> + control_register & HDSPM_AutoInp) ? "on" : "off"); + + switch (hdspm_clock_source(hdspm)) { + case HDSPM_CLOCK_SOURCE_AUTOSYNC: + clock_source = "AutoSync"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ: + clock_source = "Internal 32 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ: + clock_source = "Internal 44.1 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ: + clock_source = "Internal 48 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ: + clock_source = "Internal 64 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ: + clock_source = "Internal 88.2 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ: + clock_source = "Internal 96 kHz"; + break; + default: + clock_source = "Error"; + } + snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source); + if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { + system_clock_mode = "Slave"; + } else { + system_clock_mode = "Master"; + } + snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode); + + switch (hdspm_pref_sync_ref(hdspm)) { + case HDSPM_SYNC_FROM_WORD: + pref_sync_ref = "Word Clock"; + break; + case HDSPM_SYNC_FROM_MADI: + pref_sync_ref = "MADI Sync"; + break; + default: + pref_sync_ref = "XXXX Clock"; + break; + } + snd_iprintf(buffer, "Preferred Sync Reference: %s\n", + pref_sync_ref); + + snd_iprintf(buffer, "System Clock Frequency: %d\n", + hdspm->system_sample_rate); + + + snd_iprintf(buffer, "--- Status:\n"); + + x = status & HDSPM_madiSync; + x2 = status2 & HDSPM_wcSync; + + snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n", + (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") : + "NoLock", + (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") : + "NoLock"); + + switch (hdspm_autosync_ref(hdspm)) { + case HDSPM_AUTOSYNC_FROM_WORD: + autosync_ref = "Word Clock"; + break; + case HDSPM_AUTOSYNC_FROM_MADI: + autosync_ref = "MADI Sync"; + break; + case HDSPM_AUTOSYNC_FROM_NONE: + autosync_ref = "Input not valid"; + break; + default: + autosync_ref = "---"; + break; + } + snd_iprintf(buffer, + "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n", + autosync_ref, hdspm_external_sample_rate(hdspm), + (status & HDSPM_madiFreqMask) >> 22, + (status2 & HDSPM_wcFreqMask) >> 5); + + snd_iprintf(buffer, "Input: %s, Mode=%s\n", + (status & HDSPM_AB_int) ? "Coax" : "Optical", + (status & HDSPM_RX_64ch) ? "64 channels" : + "56 channels"); + + snd_iprintf(buffer, "\n"); +} + +static void __devinit snd_hdspm_proc_init(hdspm_t * hdspm) +{ + snd_info_entry_t *entry; + + if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) + snd_info_set_text_ops(entry, hdspm, 1024, + snd_hdspm_proc_read); +} + +/*------------------------------------------------------------ + hdspm intitialize + ------------------------------------------------------------*/ + +static int snd_hdspm_set_defaults(hdspm_t * hdspm) +{ + unsigned int i; + + /* ASSUMPTION: hdspm->lock is either held, or there is no need to + hold it (e.g. during module initalization). + */ + + /* set defaults: */ + + hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ + HDSPM_InputCoaxial | /* Input Coax not Optical */ + HDSPM_SyncRef_MADI | /* Madi is syncclock */ + HDSPM_LineOut | /* Analog output in */ + HDSPM_TX_64ch | /* transmit in 64ch mode */ + HDSPM_AutoInp; /* AutoInput chossing (takeover) */ + + /* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */ + /* ! HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */ + /* ! HDSPM_clr_tms = do not clear bits in track marks */ + + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + +#ifdef SNDRV_BIG_ENDIAN + hdspm->control2_register = HDSPM_BIGENDIAN_MODE; +#else + hdspm->control2_register = 0; +#endif + + hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register); + hdspm_compute_period_size(hdspm); + + /* silence everything */ + + all_in_all_mixer(hdspm, 0 * UNITY_GAIN); + + if (line_outs_monitor[hdspm->dev]) { + + snd_printk(KERN_INFO "HDSPM: sending all playback streams to line outs.\n"); + + for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) { + if (hdspm_write_pb_gain(hdspm, i, i, UNITY_GAIN)) + return -EIO; + } + } + + /* set a default rate so that the channel map is set up. */ + hdspm->channel_map = channel_map_madi_ss; + hdspm_set_rate(hdspm, 44100, 1); + + return 0; +} + + +/*------------------------------------------------------------ + interupt + ------------------------------------------------------------*/ + +static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + hdspm_t *hdspm = (hdspm_t *) dev_id; + unsigned int status; + int audio; + int midi0; + int midi1; + unsigned int midi0status; + unsigned int midi1status; + int schedule = 0; + + status = hdspm_read(hdspm, HDSPM_statusRegister); + + audio = status & HDSPM_audioIRQPending; + midi0 = status & HDSPM_midi0IRQPending; + midi1 = status & HDSPM_midi1IRQPending; + + if (!audio && !midi0 && !midi1) + return IRQ_NONE; + + hdspm_write(hdspm, HDSPM_interruptConfirmation, 0); + hdspm->irq_count++; + + midi0status = hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff; + midi1status = hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff; + + if (audio) { + + if (hdspm->capture_substream) + snd_pcm_period_elapsed(hdspm->pcm-> + streams + [SNDRV_PCM_STREAM_CAPTURE]. + substream); + + if (hdspm->playback_substream) + snd_pcm_period_elapsed(hdspm->pcm-> + streams + [SNDRV_PCM_STREAM_PLAYBACK]. + substream); + } + + if (midi0 && midi0status) { + /* we disable interrupts for this input until processing is done */ + hdspm->control_register &= ~HDSPM_Midi0InterruptEnable; + hdspm_write(hdspm, HDSPM_controlRegister, + hdspm->control_register); + hdspm->midi[0].pending = 1; + schedule = 1; + } + if (midi1 && midi1status) { + /* we disable interrupts for this input until processing is done */ + hdspm->control_register &= ~HDSPM_Midi1InterruptEnable; + hdspm_write(hdspm, HDSPM_controlRegister, + hdspm->control_register); + hdspm->midi[1].pending = 1; + schedule = 1; + } + if (schedule) + tasklet_hi_schedule(&hdspm->midi_tasklet); + return IRQ_HANDLED; +} + +/*------------------------------------------------------------ + pcm interface + ------------------------------------------------------------*/ + + +static snd_pcm_uframes_t snd_hdspm_hw_pointer(snd_pcm_substream_t * + substream) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + return hdspm_hw_pointer(hdspm); +} + +static char *hdspm_channel_buffer_location(hdspm_t * hdspm, + int stream, int channel) +{ + int mapped_channel; + + snd_assert(channel >= 0 + || channel < HDSPM_MAX_CHANNELS, return NULL); + + if ((mapped_channel = hdspm->channel_map[channel]) < 0) + return NULL; + + if (stream == SNDRV_PCM_STREAM_CAPTURE) { + return hdspm->capture_buffer + + mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; + } else { + return hdspm->playback_buffer + + mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; + } +} + + +/* dont know why need it ??? */ +static int snd_hdspm_playback_copy(snd_pcm_substream_t * substream, + int channel, snd_pcm_uframes_t pos, + void __user *src, snd_pcm_uframes_t count) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + char *channel_buf; + + snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4, + return -EINVAL); + + channel_buf = hdspm_channel_buffer_location(hdspm, + substream->pstr-> + stream, channel); + + snd_assert(channel_buf != NULL, return -EIO); + + return copy_from_user(channel_buf + pos * 4, src, count * 4); +} + +static int snd_hdspm_capture_copy(snd_pcm_substream_t * substream, + int channel, snd_pcm_uframes_t pos, + void __user *dst, snd_pcm_uframes_t count) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + char *channel_buf; + + snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4, + return -EINVAL); + + channel_buf = hdspm_channel_buffer_location(hdspm, + substream->pstr-> + stream, channel); + snd_assert(channel_buf != NULL, return -EIO); + return copy_to_user(dst, channel_buf + pos * 4, count * 4); +} + +static int snd_hdspm_hw_silence(snd_pcm_substream_t * substream, + int channel, snd_pcm_uframes_t pos, + snd_pcm_uframes_t count) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + char *channel_buf; + + channel_buf = + hdspm_channel_buffer_location(hdspm, substream->pstr->stream, + channel); + snd_assert(channel_buf != NULL, return -EIO); + memset(channel_buf + pos * 4, 0, count * 4); + return 0; +} + +static int snd_hdspm_reset(snd_pcm_substream_t * substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + snd_pcm_substream_t *other; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + other = hdspm->capture_substream; + else + other = hdspm->playback_substream; + + if (hdspm->running) + runtime->status->hw_ptr = hdspm_hw_pointer(hdspm); + else + runtime->status->hw_ptr = 0; + if (other) { + struct list_head *pos; + snd_pcm_substream_t *s; + snd_pcm_runtime_t *oruntime = other->runtime; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); + if (s == other) { + oruntime->status->hw_ptr = + runtime->status->hw_ptr; + break; + } + } + } + return 0; +} + +static int snd_hdspm_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * params) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + int err; + int i; + pid_t this_pid; + pid_t other_pid; + struct snd_sg_buf *sgbuf; + + + spin_lock_irq(&hdspm->lock); + + if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { + this_pid = hdspm->playback_pid; + other_pid = hdspm->capture_pid; + } else { + this_pid = hdspm->capture_pid; + other_pid = hdspm->playback_pid; + } + + if ((other_pid > 0) && (this_pid != other_pid)) { + + /* The other stream is open, and not by the same + task as this one. Make sure that the parameters + that matter are the same. + */ + + if (params_rate(params) != hdspm->system_sample_rate) { + spin_unlock_irq(&hdspm->lock); + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_RATE); + return -EBUSY; + } + + if (params_period_size(params) != hdspm->period_bytes / 4) { + spin_unlock_irq(&hdspm->lock); + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + return -EBUSY; + } + + } + /* We're fine. */ + spin_unlock_irq(&hdspm->lock); + + /* how to make sure that the rate matches an externally-set one ? */ + + spin_lock_irq(&hdspm->lock); + if ((err = hdspm_set_rate(hdspm, params_rate(params), 0)) < 0) { + spin_unlock_irq(&hdspm->lock); + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_RATE); + return err; + } + spin_unlock_irq(&hdspm->lock); + + if ((err = + hdspm_set_interrupt_interval(hdspm, + params_period_size(params))) < + 0) { + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + return err; + } + + /* Memory allocation, takashi's method, dont know if we should spinlock */ + /* malloc all buffer even if not enabled to get sure */ + /* malloc only needed bytes */ + err = + snd_pcm_lib_malloc_pages(substream, + HDSPM_CHANNEL_BUFFER_BYTES * + params_channels(params)); + if (err < 0) + return err; + + sgbuf = snd_pcm_substream_sgbuf(substream); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + + hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferOut, + params_channels(params)); + + for (i = 0; i < params_channels(params); ++i) + snd_hdspm_enable_out(hdspm, i, 1); + + hdspm->playback_buffer = + (unsigned char *) substream->runtime->dma_area; + } else { + hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn, + params_channels(params)); + + for (i = 0; i < params_channels(params); ++i) + snd_hdspm_enable_in(hdspm, i, 1); + + hdspm->capture_buffer = + (unsigned char *) substream->runtime->dma_area; + } + return 0; +} + +static int snd_hdspm_hw_free(snd_pcm_substream_t * substream) +{ + int i; + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + + /* params_channels(params) should be enough, + but to get sure in case of error */ + for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) + snd_hdspm_enable_out(hdspm, i, 0); + + hdspm->playback_buffer = NULL; + } else { + for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) + snd_hdspm_enable_in(hdspm, i, 0); + + hdspm->capture_buffer = NULL; + + } + + snd_pcm_lib_free_pages(substream); + + return 0; +} + +static int snd_hdspm_channel_info(snd_pcm_substream_t * substream, + snd_pcm_channel_info_t * info) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + int mapped_channel; + + snd_assert(info->channel < HDSPM_MAX_CHANNELS, return -EINVAL); + + if ((mapped_channel = hdspm->channel_map[info->channel]) < 0) + return -EINVAL; + + info->offset = mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; + info->first = 0; + info->step = 32; + return 0; +} + +static int snd_hdspm_ioctl(snd_pcm_substream_t * substream, + unsigned int cmd, void *arg) +{ + switch (cmd) { + case SNDRV_PCM_IOCTL1_RESET: + { + return snd_hdspm_reset(substream); + } + + case SNDRV_PCM_IOCTL1_CHANNEL_INFO: + { + snd_pcm_channel_info_t *info = arg; + return snd_hdspm_channel_info(substream, info); + } + default: + break; + } + + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + +static int snd_hdspm_trigger(snd_pcm_substream_t * substream, int cmd) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + snd_pcm_substream_t *other; + int running; + + spin_lock(&hdspm->lock); + running = hdspm->running; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + running |= 1 << substream->stream; + break; + case SNDRV_PCM_TRIGGER_STOP: + running &= ~(1 << substream->stream); + break; + default: + snd_BUG(); + spin_unlock(&hdspm->lock); + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + other = hdspm->capture_substream; + else + other = hdspm->playback_substream; + + if (other) { + struct list_head *pos; + snd_pcm_substream_t *s; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); + if (s == other) { + snd_pcm_trigger_done(s, substream); + if (cmd == SNDRV_PCM_TRIGGER_START) + running |= 1 << s->stream; + else + running &= ~(1 << s->stream); + goto _ok; + } + } + if (cmd == SNDRV_PCM_TRIGGER_START) { + if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) + && substream->stream == + SNDRV_PCM_STREAM_CAPTURE) + hdspm_silence_playback(hdspm); + } else { + if (running && + substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + hdspm_silence_playback(hdspm); + } + } else { + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + hdspm_silence_playback(hdspm); + } + _ok: + snd_pcm_trigger_done(substream, substream); + if (!hdspm->running && running) + hdspm_start_audio(hdspm); + else if (hdspm->running && !running) + hdspm_stop_audio(hdspm); + hdspm->running = running; + spin_unlock(&hdspm->lock); + + return 0; +} + +static int snd_hdspm_prepare(snd_pcm_substream_t * substream) +{ + return 0; +} + +static unsigned int period_sizes[] = + { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; + +static snd_pcm_hardware_t snd_hdspm_playback_subinfo = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_NONINTERLEAVED | + SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_DOUBLE), + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rates = (SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_64000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), + .rate_min = 32000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = HDSPM_MAX_CHANNELS, + .buffer_bytes_max = + HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, + .period_bytes_min = (64 * 4), + .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0 +}; + +static snd_pcm_hardware_t snd_hdspm_capture_subinfo = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_NONINTERLEAVED | + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rates = (SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_64000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), + .rate_min = 32000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = HDSPM_MAX_CHANNELS, + .buffer_bytes_max = + HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, + .period_bytes_min = (64 * 4), + .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0 +}; + +static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { + .count = ARRAY_SIZE(period_sizes), + .list = period_sizes, + .mask = 0 +}; + + +static int snd_hdspm_hw_rule_channels_rate(snd_pcm_hw_params_t * params, + snd_pcm_hw_rule_t * rule) +{ + hdspm_t *hdspm = rule->private; + snd_interval_t *c = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_t *r = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + + if (r->min > 48000) { + snd_interval_t t = { + .min = 1, + .max = hdspm->ds_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } else if (r->max < 64000) { + snd_interval_t t = { + .min = 1, + .max = hdspm->ss_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } + return 0; +} + +static int snd_hdspm_hw_rule_rate_channels(snd_pcm_hw_params_t * params, + snd_pcm_hw_rule_t * rule) +{ + hdspm_t *hdspm = rule->private; + snd_interval_t *c = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_t *r = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + + if (c->min <= hdspm->ss_channels) { + snd_interval_t t = { + .min = 32000, + .max = 48000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } else if (c->max > hdspm->ss_channels) { + snd_interval_t t = { + .min = 64000, + .max = 96000, + .integer = 1, + }; + + return snd_interval_refine(r, &t); + } + return 0; +} + +static int snd_hdspm_playback_open(snd_pcm_substream_t * substream) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + snd_printdd("Open device substream %d\n", substream->stream); + + spin_lock_irq(&hdspm->lock); + + snd_pcm_set_sync(substream); + + runtime->hw = snd_hdspm_playback_subinfo; + + if (hdspm->capture_substream == NULL) + hdspm_stop_audio(hdspm); + + hdspm->playback_pid = current->pid; + hdspm->playback_substream = substream; + + spin_unlock_irq(&hdspm->lock); + + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + &hw_constraints_period_sizes); + + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + snd_hdspm_hw_rule_channels_rate, hdspm, + SNDRV_PCM_HW_PARAM_RATE, -1); + + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + snd_hdspm_hw_rule_rate_channels, hdspm, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + + return 0; +} + +static int snd_hdspm_playback_release(snd_pcm_substream_t * substream) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + + spin_lock_irq(&hdspm->lock); + + hdspm->playback_pid = -1; + hdspm->playback_substream = NULL; + + spin_unlock_irq(&hdspm->lock); + + return 0; +} + + +static int snd_hdspm_capture_open(snd_pcm_substream_t * substream) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + spin_lock_irq(&hdspm->lock); + snd_pcm_set_sync(substream); + runtime->hw = snd_hdspm_capture_subinfo; + + if (hdspm->playback_substream == NULL) + hdspm_stop_audio(hdspm); + + hdspm->capture_pid = current->pid; + hdspm->capture_substream = substream; + + spin_unlock_irq(&hdspm->lock); + + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + &hw_constraints_period_sizes); + + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + snd_hdspm_hw_rule_channels_rate, hdspm, + SNDRV_PCM_HW_PARAM_RATE, -1); + + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + snd_hdspm_hw_rule_rate_channels, hdspm, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + return 0; +} + +static int snd_hdspm_capture_release(snd_pcm_substream_t * substream) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + + spin_lock_irq(&hdspm->lock); + + hdspm->capture_pid = -1; + hdspm->capture_substream = NULL; + + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_hwdep_dummy_op(snd_hwdep_t * hw, struct file *file) +{ + /* we have nothing to initialize but the call is required */ + return 0; +} + + +static int snd_hdspm_hwdep_ioctl(snd_hwdep_t * hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + hdspm_t *hdspm = (hdspm_t *) hw->private_data; + struct sndrv_hdspm_mixer_ioctl mixer; + hdspm_config_info_t info; + hdspm_version_t hdspm_version; + struct sndrv_hdspm_peak_rms_ioctl rms; + + switch (cmd) { + + + case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS: + if (copy_from_user(&rms, (void __user *)arg, sizeof(rms))) + return -EFAULT; + /* maybe there is a chance to memorymap in future so dont touch just copy */ + if(copy_to_user_fromio((void __user *)rms.peak, + hdspm->iobase+HDSPM_MADI_peakrmsbase, + sizeof(hdspm_peak_rms_t)) != 0 ) + return -EFAULT; + + break; + + + case SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO: + + spin_lock_irq(&hdspm->lock); + info.pref_sync_ref = + (unsigned char) hdspm_pref_sync_ref(hdspm); + info.wordclock_sync_check = + (unsigned char) hdspm_wc_sync_check(hdspm); + + info.system_sample_rate = hdspm->system_sample_rate; + info.autosync_sample_rate = + hdspm_external_sample_rate(hdspm); + info.system_clock_mode = + (unsigned char) hdspm_system_clock_mode(hdspm); + info.clock_source = + (unsigned char) hdspm_clock_source(hdspm); + info.autosync_ref = + (unsigned char) hdspm_autosync_ref(hdspm); + info.line_out = (unsigned char) hdspm_line_out(hdspm); + info.passthru = 0; + spin_unlock_irq(&hdspm->lock); + if (copy_to_user((void __user *) arg, &info, sizeof(info))) + return -EFAULT; + break; + + case SNDRV_HDSPM_IOCTL_GET_VERSION: + hdspm_version.firmware_rev = hdspm->firmware_rev; + if (copy_to_user((void __user *) arg, &hdspm_version, + sizeof(hdspm_version))) + return -EFAULT; + break; + + case SNDRV_HDSPM_IOCTL_GET_MIXER: + if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer))) + return -EFAULT; + if (copy_to_user + ((void __user *)mixer.mixer, hdspm->mixer, sizeof(hdspm_mixer_t))) + return -EFAULT; + break; + + default: + return -EINVAL; + } + return 0; +} + +static snd_pcm_ops_t snd_hdspm_playback_ops = { + .open = snd_hdspm_playback_open, + .close = snd_hdspm_playback_release, + .ioctl = snd_hdspm_ioctl, + .hw_params = snd_hdspm_hw_params, + .hw_free = snd_hdspm_hw_free, + .prepare = snd_hdspm_prepare, + .trigger = snd_hdspm_trigger, + .pointer = snd_hdspm_hw_pointer, + .copy = snd_hdspm_playback_copy, + .silence = snd_hdspm_hw_silence, + .page = snd_pcm_sgbuf_ops_page, +}; + +static snd_pcm_ops_t snd_hdspm_capture_ops = { + .open = snd_hdspm_capture_open, + .close = snd_hdspm_capture_release, + .ioctl = snd_hdspm_ioctl, + .hw_params = snd_hdspm_hw_params, + .hw_free = snd_hdspm_hw_free, + .prepare = snd_hdspm_prepare, + .trigger = snd_hdspm_trigger, + .pointer = snd_hdspm_hw_pointer, + .copy = snd_hdspm_capture_copy, + .page = snd_pcm_sgbuf_ops_page, +}; + +static int __devinit snd_hdspm_create_hwdep(snd_card_t * card, + hdspm_t * hdspm) +{ + snd_hwdep_t *hw; + int err; + + if ((err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw)) < 0) + return err; + + hdspm->hwdep = hw; + hw->private_data = hdspm; + strcpy(hw->name, "HDSPM hwdep interface"); + + hw->ops.open = snd_hdspm_hwdep_dummy_op; + hw->ops.ioctl = snd_hdspm_hwdep_ioctl; + hw->ops.release = snd_hdspm_hwdep_dummy_op; + + return 0; +} + + +/*------------------------------------------------------------ + memory interface + ------------------------------------------------------------*/ +static int __devinit snd_hdspm_preallocate_memory(hdspm_t * hdspm) +{ + int err; + snd_pcm_t *pcm; + size_t wanted; + + pcm = hdspm->pcm; + + wanted = HDSPM_DMA_AREA_BYTES + 4096; /* dont know why, but it works */ + + if ((err = + snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(hdspm->pci), + wanted, + wanted)) < 0) { + snd_printdd("Could not preallocate %d Bytes\n", wanted); + + return err; + } else + snd_printdd(" Preallocated %d Bytes\n", wanted); + + return 0; +} + +static int snd_hdspm_memory_free(hdspm_t * hdspm) +{ + snd_printdd("memory_free_for_all %p\n", hdspm->pcm); + + snd_pcm_lib_preallocate_free_for_all(hdspm->pcm); + return 0; +} + + +static void hdspm_set_sgbuf(hdspm_t * hdspm, struct snd_sg_buf *sgbuf, + unsigned int reg, int channels) +{ + int i; + for (i = 0; i < (channels * 16); i++) + hdspm_write(hdspm, reg + 4 * i, + snd_pcm_sgbuf_get_addr(sgbuf, + (size_t) 4096 * i)); +} + +/* ------------- ALSA Devices ---------------------------- */ +static int __devinit snd_hdspm_create_pcm(snd_card_t * card, + hdspm_t * hdspm) +{ + snd_pcm_t *pcm; + int err; + + if ((err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm)) < 0) + return err; + + hdspm->pcm = pcm; + pcm->private_data = hdspm; + strcpy(pcm->name, hdspm->card_name); + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_hdspm_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_hdspm_capture_ops); + + pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; + + if ((err = snd_hdspm_preallocate_memory(hdspm)) < 0) + return err; + + return 0; +} + +static inline void snd_hdspm_initialize_midi_flush(hdspm_t * hdspm) +{ + snd_hdspm_flush_midi_input(hdspm, 0); + snd_hdspm_flush_midi_input(hdspm, 1); +} + +static int __devinit snd_hdspm_create_alsa_devices(snd_card_t * card, + hdspm_t * hdspm) +{ + int err; + + snd_printdd("Create card...\n"); + if ((err = snd_hdspm_create_pcm(card, hdspm)) < 0) + return err; + + if ((err = snd_hdspm_create_midi(card, hdspm, 0)) < 0) + return err; + + if ((err = snd_hdspm_create_midi(card, hdspm, 1)) < 0) + return err; + + if ((err = snd_hdspm_create_controls(card, hdspm)) < 0) + return err; + + if ((err = snd_hdspm_create_hwdep(card, hdspm)) < 0) + return err; + + snd_printdd("proc init...\n"); + snd_hdspm_proc_init(hdspm); + + hdspm->system_sample_rate = -1; + hdspm->last_external_sample_rate = -1; + hdspm->last_internal_sample_rate = -1; + hdspm->playback_pid = -1; + hdspm->capture_pid = -1; + hdspm->capture_substream = NULL; + hdspm->playback_substream = NULL; + + snd_printdd("Set defaults...\n"); + if ((err = snd_hdspm_set_defaults(hdspm)) < 0) + return err; + + snd_printdd("Update mixer controls...\n"); + hdspm_update_simple_mixer_controls(hdspm); + + snd_printdd("Initializeing complete ???\n"); + + if ((err = snd_card_register(card)) < 0) { + snd_printk(KERN_ERR "HDSPM: error registering card\n"); + return err; + } + + snd_printdd("... yes now\n"); + + return 0; +} + +static int __devinit snd_hdspm_create(snd_card_t * card, hdspm_t * hdspm, + int precise_ptr, int enable_monitor) +{ + struct pci_dev *pci = hdspm->pci; + int err; + int i; + + unsigned long io_extent; + + hdspm->irq = -1; + hdspm->irq_count = 0; + + hdspm->midi[0].rmidi = NULL; + hdspm->midi[1].rmidi = NULL; + hdspm->midi[0].input = NULL; + hdspm->midi[1].input = NULL; + hdspm->midi[0].output = NULL; + hdspm->midi[1].output = NULL; + spin_lock_init(&hdspm->midi[0].lock); + spin_lock_init(&hdspm->midi[1].lock); + hdspm->iobase = NULL; + hdspm->control_register = 0; + hdspm->control2_register = 0; + + hdspm->playback_buffer = NULL; + hdspm->capture_buffer = NULL; + + for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) + hdspm->playback_mixer_ctls[i] = NULL; + hdspm->mixer = NULL; + + hdspm->card = card; + + spin_lock_init(&hdspm->lock); + + tasklet_init(&hdspm->midi_tasklet, + hdspm_midi_tasklet, (unsigned long) hdspm); + + pci_read_config_word(hdspm->pci, + PCI_CLASS_REVISION, &hdspm->firmware_rev); + + strcpy(card->driver, "HDSPM"); + strcpy(card->mixername, "Xilinx FPGA"); + hdspm->card_name = "RME HDSPM MADI"; + + if ((err = pci_enable_device(pci)) < 0) + return err; + + pci_set_master(hdspm->pci); + + if ((err = pci_request_regions(pci, "hdspm")) < 0) + return err; + + hdspm->port = pci_resource_start(pci, 0); + io_extent = pci_resource_len(pci, 0); + + snd_printdd("grabbed memory region 0x%lx-0x%lx\n", + hdspm->port, hdspm->port + io_extent - 1); + + + if ((hdspm->iobase = ioremap_nocache(hdspm->port, io_extent)) == NULL) { + snd_printk(KERN_ERR "HDSPM: unable to remap region 0x%lx-0x%lx\n", + hdspm->port, hdspm->port + io_extent - 1); + return -EBUSY; + } + snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n", + (unsigned long)hdspm->iobase, hdspm->port, + hdspm->port + io_extent - 1); + + if (request_irq(pci->irq, snd_hdspm_interrupt, + SA_INTERRUPT | SA_SHIRQ, "hdspm", + (void *) hdspm)) { + snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq); + return -EBUSY; + } + + snd_printdd("use IRQ %d\n", pci->irq); + + hdspm->irq = pci->irq; + hdspm->precise_ptr = precise_ptr; + + hdspm->monitor_outs = enable_monitor; + + snd_printdd("kmalloc Mixer memory of %d Bytes\n", + sizeof(hdspm_mixer_t)); + if ((hdspm->mixer = + (hdspm_mixer_t *) kmalloc(sizeof(hdspm_mixer_t), GFP_KERNEL)) + == NULL) { + snd_printk(KERN_ERR "HDSPM: unable to kmalloc Mixer memory of %d Bytes\n", + (int)sizeof(hdspm_mixer_t)); + return err; + } + + hdspm->ss_channels = MADI_SS_CHANNELS; + hdspm->ds_channels = MADI_DS_CHANNELS; + hdspm->qs_channels = MADI_QS_CHANNELS; + + snd_printdd("create alsa devices.\n"); + if ((err = snd_hdspm_create_alsa_devices(card, hdspm)) < 0) + return err; + + snd_hdspm_initialize_midi_flush(hdspm); + + return 0; +} + +static int snd_hdspm_free(hdspm_t * hdspm) +{ + + if (hdspm->port) { + + /* stop th audio, and cancel all interrupts */ + hdspm->control_register &= + ~(HDSPM_Start | HDSPM_AudioInterruptEnable + | HDSPM_Midi0InterruptEnable | + HDSPM_Midi1InterruptEnable); + hdspm_write(hdspm, HDSPM_controlRegister, + hdspm->control_register); + } + + if (hdspm->irq >= 0) + free_irq(hdspm->irq, (void *) hdspm); + + + if (hdspm->mixer) + kfree(hdspm->mixer); + + if (hdspm->iobase) + iounmap(hdspm->iobase); + + snd_hdspm_memory_free(hdspm); + + if (hdspm->port) + pci_release_regions(hdspm->pci); + + pci_disable_device(hdspm->pci); + return 0; +} + +static void snd_hdspm_card_free(snd_card_t * card) +{ + hdspm_t *hdspm = (hdspm_t *) card->private_data; + + if (hdspm) + snd_hdspm_free(hdspm); +} + +static int __devinit snd_hdspm_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + hdspm_t *hdspm; + snd_card_t *card; + int err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + if (!(card = snd_card_new(index[dev], id[dev], + THIS_MODULE, sizeof(hdspm_t)))) + return -ENOMEM; + + hdspm = (hdspm_t *) card->private_data; + card->private_free = snd_hdspm_card_free; + hdspm->dev = dev; + hdspm->pci = pci; + + if ((err = + snd_hdspm_create(card, hdspm, precise_ptr[dev], + enable_monitor[dev])) < 0) { + snd_card_free(card); + return err; + } + + strcpy(card->shortname, "HDSPM MADI"); + sprintf(card->longname, "%s at 0x%lx, irq %d", hdspm->card_name, + hdspm->port, hdspm->irq); + + if ((err = snd_card_register(card)) < 0) { + snd_card_free(card); + return err; + } + + pci_set_drvdata(pci, card); + + dev++; + return 0; +} + +static void __devexit snd_hdspm_remove(struct pci_dev *pci) +{ + snd_card_free(pci_get_drvdata(pci)); + pci_set_drvdata(pci, NULL); +} + +static struct pci_driver driver = { + .name = "RME Hammerfall DSP MADI", + .id_table = snd_hdspm_ids, + .probe = snd_hdspm_probe, + .remove = __devexit_p(snd_hdspm_remove), +}; + + +static int __init alsa_card_hdspm_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_hdspm_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_hdspm_init) +module_exit(alsa_card_hdspm_exit) -- cgit v0.10.2 From 5470440a2a1f5e8afe7df306fdbf26e6b1143975 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 3 Jun 2005 11:27:00 +0200 Subject: [ALSA] Add documentation for HDSP MADI Documentation Added documentation for HDSP MADI driver by Winfried Ritsch. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 812ed2b..ced9a6e 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -674,6 +674,17 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. stage of boot sequence. See "Early Buffer Allocation" section. + Module snd-hdspm + ---------------- + + Module for RME HDSP MADI board. + + precise_ptr - Enable precise pointer, or disable. + line_outs_monitor - Send playback streams to analog outs by default. + enable_monitor - Enable Analog Out on Channel 63/64 by default. + + See hdspm.txt for details. + Module snd-ice1712 ------------------ diff --git a/Documentation/sound/alsa/hdspm.txt b/Documentation/sound/alsa/hdspm.txt new file mode 100644 index 0000000..7a67ff7 --- /dev/null +++ b/Documentation/sound/alsa/hdspm.txt @@ -0,0 +1,362 @@ +Software Interface ALSA-DSP MADI Driver + +(translated from German, so no good English ;-), +2004 - winfried ritsch + + + + Full functionality has been added to the driver. Since some of + the Controls and startup-options are ALSA-Standard and only the + special Controls are described and discussed below. + + + hardware functionality: + + + Audio transmission: + + number of channels -- depends on transmission mode + + The number of channels chosen is from 1..Nmax. The reason to + use for a lower number of channels is only resource allocation, + since unused DMA channels are disabled and less memory is + allocated. So also the throughput of the PCI system can be + scaled. (Only important for low performance boards). + + Single Speed -- 1..64 channels + + (Note: Choosing the 56channel mode for transmission or as + receiver, only 56 are transmitted/received over the MADI, but + all 64 channels are available for the mixer, so channel count + for the driver) + + Double Speed -- 1..32 channels + + Note: Choosing the 56-channel mode for + transmission/receive-mode , only 28 are transmitted/received + over the MADI, but all 32 channels are available for the mixer, + so channel count for the driver + + + Quad Speed -- 1..16 channels + + Note: Choosing the 56-channel mode for + transmission/receive-mode , only 14 are transmitted/received + over the MADI, but all 16 channels are available for the mixer, + so channel count for the driver + + Format -- signed 32 Bit Little Endian (SNDRV_PCM_FMTBIT_S32_LE) + + Sample Rates -- + + Single Speed -- 32000, 44100, 48000 + + Double Speed -- 64000, 88200, 96000 (untested) + + Quad Speed -- 128000, 176400, 192000 (untested) + + access-mode -- MMAP (memory mapped), Not interleaved + (PCM_NON-INTERLEAVED) + + buffer-sizes -- 64,128,256,512,1024,2048,8192 Samples + + fragments -- 2 + + Hardware-pointer -- 2 Modi + + + The Card supports the readout of the actual Buffer-pointer, + where DMA reads/writes. Since of the bulk mode of PCI it is only + 64 Byte accurate. SO it is not really usable for the + ALSA-mid-level functions (here the buffer-ID gives a better + result), but if MMAP is used by the application. Therefore it + can be configured at load-time with the parameter + precise-pointer. + + + (Hint: Experimenting I found that the pointer is maximum 64 to + large never to small. So if you subtract 64 you always have a + safe pointer for writing, which is used on this mode inside + ALSA. In theory now you can get now a latency as low as 16 + Samples, which is a quarter of the interrupt possibilities.) + + Precise Pointer -- off + interrupt used for pointer-calculation + + Precise Pointer -- on + hardware pointer used. + + Controller: + + + Since DSP-MADI-Mixer has 8152 Fader, it does not make sense to + use the standard mixer-controls, since this would break most of + (especially graphic) ALSA-Mixer GUIs. So Mixer control has be + provided by a 2-dimensional controller using the + hwdep-interface. + + Also all 128+256 Peak and RMS-Meter can be accessed via the + hwdep-interface. Since it could be a performance problem always + copying and converting Peak and RMS-Levels even if you just need + one, I decided to export the hardware structure, so that of + needed some driver-guru can implement a memory-mapping of mixer + or peak-meters over ioctl, or also to do only copying and no + conversion. A test-application shows the usage of the controller. + + Latency Controls --- not implemented !!! + + + Note: Within the windows-driver the latency is accessible of a + control-panel, but buffer-sizes are controlled with ALSA from + hwparams-calls and should not be changed in run-state, I did not + implement it here. + + + System Clock -- suspended !!!! + + Name -- "System Clock Mode" + + Access -- Read Write + + Values -- "Master" "Slave" + + + !!!! This is a hardware-function but is in conflict with the + Clock-source controller, which is a kind of ALSA-standard. I + makes sense to set the card to a special mode (master at some + frequency or slave), since even not using an Audio-application + a studio should have working synchronisations setup. So use + Clock-source-controller instead !!!! + + Clock Source + + Name -- "Sample Clock Source" + + Access -- Read Write + + Values -- "AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", + "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", + "Internal 96.0 kHz" + + Choose between Master at a specific Frequency and so also the + Speed-mode or Slave (Autosync). Also see "Preferred Sync Ref" + + + !!!! This is no pure hardware function but was implemented by + ALSA by some ALSA-drivers before, so I use it also. !!! + + + Preferred Sync Ref + + Name -- "Preferred Sync Reference" + + Access -- Read Write + + Values -- "Word" "MADI" + + + Within the Auto-sync-Mode the preferred Sync Source can be + chosen. If it is not available another is used if possible. + + Note: Since MADI has a much higher bit-rate than word-clock, the + card should synchronise better in MADI Mode. But since the + RME-PLL is very good, there are almost no problems with + word-clock too. I never found a difference. + + + TX 64 channel --- + + Name -- "TX 64 channels mode" + + Access -- Read Write + + Values -- 0 1 + + Using 64-channel-modus (1) or 56-channel-modus for + MADI-transmission (0). + + + Note: This control is for output only. Input-mode is detected + automatically from hardware sending MADI. + + + Clear TMS --- + + Name -- "Clear Track Marker" + + Access -- Read Write + + Values -- 0 1 + + + Don't use to lower 5 Audio-bits on AES as additional Bits. + + + Safe Mode oder Auto Input --- + + Name -- "Safe Mode" + + Access -- Read Write + + Values -- 0 1 + + (default on) + + If on (1), then if either the optical or coaxial connection + has a failure, there is a takeover to the working one, with no + sample failure. Its only useful if you use the second as a + backup connection. + + Input --- + + Name -- "Input Select" + + Access -- Read Write + + Values -- optical coaxial + + + Choosing the Input, optical or coaxial. If Safe-mode is active, + this is the preferred Input. + +-------------- Mixer ---------------------- + + Mixer + + Name -- "Mixer" + + Access -- Read Write + + Values - + + + Here as a first value the channel-index is taken to get/set the + corresponding mixer channel, where 0-63 are the input to output + fader and 64-127 the playback to outputs fader. Value 0 + is channel muted 0 and 32768 an amplification of 1. + + Chn 1-64 + + fast mixer for the ALSA-mixer utils. The diagonal of the + mixer-matrix is implemented from playback to output. + + + Line Out + + Name -- "Line Out" + + Access -- Read Write + + Values -- 0 1 + + Switching on and off the analog out, which has nothing to do + with mixing or routing. the analog outs reflects channel 63,64. + + +--- information (only read access): + + Sample Rate + + Name -- "System Sample Rate" + + Access -- Read-only + + getting the sample rate. + + + External Rate measured + + Name -- "External Rate" + + Access -- Read only + + + Should be "Autosync Rate", but Name used is + ALSA-Scheme. External Sample frequency liked used on Autosync is + reported. + + + MADI Sync Status + + Name -- "MADI Sync Lock Status" + + Access -- Read + + Values -- 0,1,2 + + MADI-Input is 0=Unlocked, 1=Locked, or 2=Synced. + + + Word Clock Sync Status + + Name -- "Word Clock Lock Status" + + Access -- Read + + Values -- 0,1,2 + + Word Clock Input is 0=Unlocked, 1=Locked, or 2=Synced. + + AutoSync + + Name -- "AutoSync Reference" + + Access -- Read + + Values -- "WordClock", "MADI", "None" + + Sync-Reference is either "WordClock", "MADI" or none. + + RX 64ch --- noch nicht implementiert + + MADI-Receiver is in 64 channel mode oder 56 channel mode. + + + AB_inp --- not tested + + Used input for Auto-Input. + + + actual Buffer Position --- not implemented + + !!! this is a ALSA internal function, so no control is used !!! + + + +Calling Parameter: + + index int array (min = 1, max = 8), + "Index value for RME HDSPM interface." card-index within ALSA + + note: ALSA-standard + + id string array (min = 1, max = 8), + "ID string for RME HDSPM interface." + + note: ALSA-standard + + enable int array (min = 1, max = 8), + "Enable/disable specific HDSPM sound-cards." + + note: ALSA-standard + + precise_ptr int array (min = 1, max = 8), + "Enable precise pointer, or disable." + + note: Use only when the application supports this (which is a special case). + + line_outs_monitor int array (min = 1, max = 8), + "Send playback streams to analog outs by default." + + + note: each playback channel is mixed to the same numbered output + channel (routed). This is against the ALSA-convention, where all + channels have to be muted on after loading the driver, but was + used before on other cards, so i historically use it again) + + + + enable_monitor int array (min = 1, max = 8), + "Enable Analog Out on Channel 63/64 by default." + + note: here the analog output is enabled (but not routed). \ No newline at end of file -- cgit v0.10.2 From c82bf829c01079e77286481884eacb229310b4f0 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 4 Jun 2005 15:03:06 +0200 Subject: [ALSA] ca0106: Fix 96000 Hz audio playback. CA0106 driver Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index beac9da..da09cab 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -154,7 +154,7 @@ * bit 9 0 = Mute / 1 = Analog out. * bit 10 0 = Line-in / 1 = Mic-in. * bit 11 0 = ? / 1 = ? - * bit 12 0 = ? / 1 = ? + * bit 12 0 = 48 Khz / 1 = 96 Khz Analog out on SB Live 24bit. * bit 13 0 = ? / 1 = ? * bit 14 0 = Mute / 1 = Analog out * bit 15 0 = ? / 1 = ? diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 0ec0c3e..95c2892 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1277,7 +1277,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ - outl(0x005f4301, chip->port+GPIO); /* Analog */ + outl(0x005f5301, chip->port+GPIO); /* Analog */ } else { outl(0x0, chip->port+GPIO); outl(0x005f03a3, chip->port+GPIO); /* Analog */ -- cgit v0.10.2 From 96d078154bca743512102e370a03fb71d56478f5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 7 Jun 2005 08:56:24 +0200 Subject: [ALSA] via82xx - fixed entry for Umax AB 595T (VIA K8N800A - VT8237) VIA82xx driver As the original reporter noted, the NO_VRA must be used for loud volumes. Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index e329e19..e861a01 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2159,7 +2159,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ { .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ { .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ - { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_ENABLE }, /* Umax AB 595T (VIA K8N800A - VT8237) */ + { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_NO_VRA }, /* Umax AB 595T (VIA K8N800A - VT8237) */ { .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ { .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ { .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ -- cgit v0.10.2 From 4a19faee6332fad8f81eaa98cf0e3be15a2366c4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Jun 2005 14:43:58 +0200 Subject: [ALSA] Fix the handling of amp cache in hda-codec HDA Codec driver Fixed the handling of amp cache in hda-codec driver. The confliction of cache values with different indices should be fixed now. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e6efaed..cb3a761 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -566,9 +566,10 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stre * amp access functions */ -#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + (idx) * 32 + (dir) * 64) +/* FIXME: more better hash key? */ +#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) #define INFO_AMP_CAPS (1<<0) -#define INFO_AMP_VOL (1<<1) +#define INFO_AMP_VOL(ch) (1 << (1 + (ch))) /* initialize the hash table */ static void init_amp_hash(struct hda_codec *codec) @@ -627,28 +628,29 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) /* * read the current volume to info - * if the cache exists, read from the cache. + * if the cache exists, read the cache value. */ -static void get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, +static unsigned int get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, hda_nid_t nid, int ch, int direction, int index) { u32 val, parm; - if (info->status & (INFO_AMP_VOL << ch)) - return; + if (info->status & INFO_AMP_VOL(ch)) + return info->vol[ch]; parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; parm |= index; val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); info->vol[ch] = val & 0xff; - info->status |= INFO_AMP_VOL << ch; + info->status |= INFO_AMP_VOL(ch); + return info->vol[ch]; } /* - * write the current volume in info to the h/w + * write the current volume in info to the h/w and update the cache */ -static void put_vol_mute(struct hda_codec *codec, +static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, hda_nid_t nid, int ch, int direction, int index, int val) { u32 parm; @@ -658,30 +660,34 @@ static void put_vol_mute(struct hda_codec *codec, parm |= index << AC_AMP_SET_INDEX_SHIFT; parm |= val; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); + info->vol[ch] = val; } /* - * read/write AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. + * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. */ static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) { struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); if (! info) return 0; - get_vol_mute(codec, info, nid, ch, direction, index); - return info->vol[ch]; + return get_vol_mute(codec, info, nid, ch, direction, index); } -static int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val) +/* + * update the AMP value, mask = bit mask to set, val = the value + */ +static int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val) { struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); + if (! info) return 0; - get_vol_mute(codec, info, nid, ch, direction, idx); + val &= mask; + val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; if (info->vol[ch] == val && ! codec->in_resume) return 0; - put_vol_mute(codec, nid, ch, direction, idx, val); - info->vol[ch] = val; + put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } @@ -740,21 +746,15 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t int chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); int idx = get_amp_index(kcontrol); - int val; long *valp = ucontrol->value.integer.value; int change = 0; - if (chs & 1) { - val = *valp & 0x7f; - val |= snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80; - change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); - valp++; - } - if (chs & 2) { - val = *valp & 0x7f; - val |= snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80; - change |= snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val); - } + if (chs & 1) + change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, + 0x7f, *valp); + if (chs & 2) + change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, + 0x7f, valp[1]); return change; } @@ -793,21 +793,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t int chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); int idx = get_amp_index(kcontrol); - int val; long *valp = ucontrol->value.integer.value; int change = 0; - if (chs & 1) { - val = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; - val |= *valp ? 0 : 0x80; - change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); - valp++; - } - if (chs & 2) { - val = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f; - val |= *valp ? 0 : 0x80; - change = snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val); - } + if (chs & 1) + change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, + 0x80, *valp ? 0 : 0x80); + if (chs & 2) + change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, + 0x80, valp[1] ? 0 : 0x80); return change; } -- cgit v0.10.2 From ead9b7c39984f509dc42d81200109c01a0b689c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Jun 2005 14:48:19 +0200 Subject: [ALSA] Fix the PCM mixer switch for AD1986A HDA Codec driver Fix the PCM mixer switch for AD1986a (it was a typo). Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index caa4869..2fd05bb 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -318,7 +318,7 @@ static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_ return change; } -#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_volume_info +#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { -- cgit v0.10.2 From 41e41f1f3495c6a7443977d2842d6911e3dcf31c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Jun 2005 14:48:49 +0200 Subject: [ALSA] Fix the analog loopback volumes of ALC codecs HDA Codec driver Fix the analog loopback volumes of ALC codecs. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ee1c4cd..0ca5151 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -78,6 +78,8 @@ struct alc_spec { /* PCM information */ struct hda_pcm pcm_rec[2]; + + struct semaphore bind_mutex; }; /* DAC/ADC assignment */ @@ -363,6 +365,73 @@ static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc /* + * bound volume controls + * + * bind multiple volumes (# indices, from 0) + */ + +#define AMP_VAL_IDX_SHIFT 19 +#define AMP_VAL_IDX_MASK (0x0f<<19) + +static int alc_bind_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + unsigned long pval; + + down(&spec->bind_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ + snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + kcontrol->private_value = pval; + up(&spec->bind_mutex); + return 0; +} + +static int alc_bind_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + unsigned long pval; + + down(&spec->bind_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ + snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); + kcontrol->private_value = pval; + up(&spec->bind_mutex); + return 0; +} + +static int alc_bind_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + unsigned long pval; + int i, indices, change = 0; + + down(&spec->bind_mutex); + pval = kcontrol->private_value; + indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; + for (i = 0; i < indices; i++) { + kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT); + change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); + } + kcontrol->private_value = pval; + up(&spec->bind_mutex); + return change; +} + +#define ALC_BIND_VOL_MONO(xname, nid, channel, indices, direction) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .info = alc_bind_vol_info, \ + .get = alc_bind_vol_get, \ + .put = alc_bind_vol_put, \ + .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } + +#define ALC_BIND_VOL(xname,nid,indices,dir) ALC_BIND_VOL_MONO(xname,nid,3,indices,dir) + +/* */ /* 3-stack mode @@ -370,12 +439,12 @@ static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc * HP=0x19 */ static snd_kcontrol_new_t alc880_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Surround Playback Volume", 0x0f, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), + ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x18, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x18, 2, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -388,7 +457,7 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Headphone Playback Volume", 0x0d, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), /* We don't use NID 0x07 - see above */ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), @@ -423,15 +492,15 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { * Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19 */ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Surround Playback Volume", 0x0f, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), + ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Side Playback Volume", 0x0d, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Side Playback Switch", 0x1a, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), @@ -443,7 +512,7 @@ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), */ HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), /* We don't use NID 0x07 - see above */ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), @@ -506,9 +575,9 @@ static snd_kcontrol_new_t alc880_w810_base_mixer[] = { }; static snd_kcontrol_new_t alc880_z71v_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Headphone Playback Volume", 0x0d, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), @@ -1215,10 +1284,10 @@ static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * } static snd_kcontrol_new_t alc880_test_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), + ALC_BIND_VOL("Surround Playback Volume", 0x0d, 2, HDA_OUTPUT), + ALC_BIND_VOL("CLFE Playback Volume", 0x0e, 2, HDA_OUTPUT), + ALC_BIND_VOL("Side Playback Volume", 0x0f, 2, HDA_OUTPUT), PIN_CTL_TEST("Front Pin Mode", 0x14), PIN_CTL_TEST("Surround Pin Mode", 0x15), PIN_CTL_TEST("CLFE Pin Mode", 0x16), @@ -1402,6 +1471,7 @@ static int patch_alc880(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + init_MUTEX(&spec->bind_mutex); codec->spec = spec; board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); @@ -1551,7 +1621,7 @@ static struct alc_channel_mode alc260_modes[1] = { }; snd_kcontrol_new_t alc260_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x08, 2, HDA_OUTPUT), /* use LINE2 for the output */ /* HDA_CODEC_MUTE("Front Playback Switch", 0x0f, 0x0, HDA_OUTPUT), */ HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -1565,9 +1635,9 @@ snd_kcontrol_new_t alc260_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Headphone Playback Volume", 0x09, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + ALC_BIND_VOL_MONO("Mono Playback Volume", 0x0a, 1, 2, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), @@ -1660,6 +1730,7 @@ static int patch_alc260(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + init_MUTEX(&spec->bind_mutex); codec->spec = spec; spec->mixers[spec->num_mixers] = alc260_base_mixer; @@ -1757,15 +1828,15 @@ static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ static snd_kcontrol_new_t alc882_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Surround Playback Volume", 0x0d, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), + ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Side Playback Volume", 0x0f, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Side Playback Switch", 0x17, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -1895,6 +1966,7 @@ static int patch_alc882(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + init_MUTEX(&spec->bind_mutex); codec->spec = spec; spec->mixers[spec->num_mixers] = alc882_base_mixer; -- cgit v0.10.2 From 1ccc67d692c52dcc02e70206338ff36ac145a939 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Jun 2005 14:49:31 +0200 Subject: [ALSA] Disable MPU401 on SIS7018 Trident driver Disable MPU401 support on SIS7018 since it results in kernel freeze. Signed-off-by: Takashi Iwai diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 5d21cb8..940d531 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -143,7 +143,8 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, return err; } } - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, + if (trident->device != TRIDENT_DEVICE_ID_SI7018 && + (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, trident->midi_port, 1, trident->irq, 0, &trident->rmidi)) < 0) { snd_card_free(card); -- cgit v0.10.2 From 3e289f16ec2e08bbb37ce57a31386ed135887da4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2005 19:45:09 +0200 Subject: [ALSA] hda-codec - Print all AMP IN values HDA generic driver Print all AMP IN values when multiple nodes are connected. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 15df716..de1217b 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -68,21 +68,27 @@ static void print_amp_caps(snd_info_buffer_t *buffer, static void print_amp_vals(snd_info_buffer_t *buffer, struct hda_codec *codec, hda_nid_t nid, - int dir, int stereo) + int dir, int stereo, int indices) { unsigned int val; - if (stereo) { + int i; + + if (dir == HDA_OUTPUT) + dir = AC_AMP_GET_OUTPUT; + else + dir = AC_AMP_GET_INPUT; + for (i = 0; i < indices; i++) { + snd_iprintf(buffer, " ["); + if (stereo) { + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_LEFT | dir | i); + snd_iprintf(buffer, "0x%02x ", val); + } val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_LEFT | - (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : - AC_AMP_GET_INPUT)); - snd_iprintf(buffer, "0x%02x ", val); + AC_AMP_GET_RIGHT | dir | i); + snd_iprintf(buffer, "0x%02x]", val); } - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_RIGHT | - (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : - AC_AMP_GET_INPUT)); - snd_iprintf(buffer, "0x%02x\n", val); + snd_iprintf(buffer, "\n"); } static void print_pcm_caps(snd_info_buffer_t *buffer, @@ -217,6 +223,9 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) unsigned int wid_caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + int conn_len = 0; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; + snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, get_wid_type_name(wid_type), wid_caps); if (wid_caps & AC_WCAP_STEREO) @@ -231,19 +240,23 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) snd_iprintf(buffer, " Amp-Out"); snd_iprintf(buffer, "\n"); + if (wid_caps & AC_WCAP_CONN_LIST) + conn_len = snd_hda_get_connections(codec, nid, conn, + HDA_MAX_CONNECTIONS); + if (wid_caps & AC_WCAP_IN_AMP) { snd_iprintf(buffer, " Amp-In caps: "); print_amp_caps(buffer, codec, nid, HDA_INPUT); snd_iprintf(buffer, " Amp-In vals: "); print_amp_vals(buffer, codec, nid, HDA_INPUT, - wid_caps & AC_WCAP_STEREO); + wid_caps & AC_WCAP_STEREO, conn_len); } if (wid_caps & AC_WCAP_OUT_AMP) { snd_iprintf(buffer, " Amp-Out caps: "); print_amp_caps(buffer, codec, nid, HDA_OUTPUT); snd_iprintf(buffer, " Amp-Out vals: "); print_amp_vals(buffer, codec, nid, HDA_OUTPUT, - wid_caps & AC_WCAP_STEREO); + wid_caps & AC_WCAP_STEREO, 1); } if (wid_type == AC_WID_PIN) { @@ -267,10 +280,7 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) } if (wid_caps & AC_WCAP_CONN_LIST) { - hda_nid_t conn[HDA_MAX_CONNECTIONS]; - int c, conn_len, curr = -1; - conn_len = snd_hda_get_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); + int c, curr = -1; if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) curr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); -- cgit v0.10.2 From 4b3acaf5b56f53ef259a6ddf8e17dcb529631d9b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2005 19:48:10 +0200 Subject: [ALSA] hda-codec - Feed front signals to all surrounds HDA Codec driver Feed front signals to all surround channels if no data is given for surround channels. It seems that CLFE works as expected (only center outputs) even if connected from the front line - at least on my test system. If this change causes problems on other system (e.g. only the left channel is transferred to the center channel), please let me know... Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index cb3a761..8805928 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1682,11 +1682,12 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_o snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); /* surrounds */ for (i = 1; i < mout->num_dacs; i++) { - if (i == HDA_REAR && chs == 2) /* copy front to rear */ - snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, format); - else if (chs >= (i + 1) * 2) /* independent out */ + if (chs >= (i + 1) * 2) /* independent out */ snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2, format); + else /* copy front */ + snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, + format); } return 0; } -- cgit v0.10.2 From 05acb863a27e7f82d81c422b977415fa80b99f96 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2005 19:50:25 +0200 Subject: [ALSA] hda-codec - Clean up and fix ALC-codec support code HDA Codec driver Clean up and fix ALC-codec support code. The last addition of bound volume is fixed now to handle correctly the bound 'mute switches'. The analog loopback should work better. The init verbs are fixed together with this change. The numbers are replaced with macros for better readability. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0ca5151..84ae90c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -101,7 +101,7 @@ static hda_nid_t alc880_z71v_dac_nids[1] = { #if 0 /* The datasheet says the node 0x07 is connected from inputs, - * but it shows zero connection in the real implementation. + * but it shows zero connection in the real implementation on some devices. */ static hda_nid_t alc880_adc_nids[3] = { /* ADC0-2 */ @@ -373,7 +373,7 @@ static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc #define AMP_VAL_IDX_SHIFT 19 #define AMP_VAL_IDX_MASK (0x0f<<19) -static int alc_bind_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +static int alc_bind_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; @@ -382,13 +382,13 @@ static int alc_bind_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinf down(&spec->bind_mutex); pval = kcontrol->private_value; kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ - snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + snd_hda_mixer_amp_switch_info(kcontrol, uinfo); kcontrol->private_value = pval; up(&spec->bind_mutex); return 0; } -static int alc_bind_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int alc_bind_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; @@ -397,13 +397,13 @@ static int alc_bind_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon down(&spec->bind_mutex); pval = kcontrol->private_value; kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ - snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); + snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); kcontrol->private_value = pval; up(&spec->bind_mutex); return 0; } -static int alc_bind_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; @@ -415,21 +415,21 @@ static int alc_bind_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; for (i = 0; i < indices; i++) { kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT); - change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); + change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); } kcontrol->private_value = pval; up(&spec->bind_mutex); return change; } -#define ALC_BIND_VOL_MONO(xname, nid, channel, indices, direction) \ +#define ALC_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = alc_bind_vol_info, \ - .get = alc_bind_vol_get, \ - .put = alc_bind_vol_put, \ + .info = alc_bind_switch_info, \ + .get = alc_bind_switch_get, \ + .put = alc_bind_switch_put, \ .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } -#define ALC_BIND_VOL(xname,nid,indices,dir) ALC_BIND_VOL_MONO(xname,nid,3,indices,dir) +#define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) /* */ @@ -439,14 +439,14 @@ static int alc_bind_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon * HP=0x19 */ static snd_kcontrol_new_t alc880_base_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Surround Playback Volume", 0x0f, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x1a, 0x0, HDA_OUTPUT), - ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), - ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x18, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x18, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x1a, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -457,8 +457,8 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - ALC_BIND_VOL("Headphone Playback Volume", 0x0d, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), /* We don't use NID 0x07 - see above */ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), @@ -492,16 +492,16 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { * Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19 */ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Surround Playback Volume", 0x0f, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x17, 0x0, HDA_OUTPUT), - ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), - ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Side Playback Volume", 0x0d, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x1a, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -575,10 +575,10 @@ static snd_kcontrol_new_t alc880_w810_base_mixer[] = { }; static snd_kcontrol_new_t alc880_z71v_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Headphone Playback Volume", 0x0d, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -636,51 +636,66 @@ static int alc_build_controls(struct hda_codec *codec) * initialize the codec volumes, etc */ +#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) +#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 +#define PIN_IN 0x20 +#define PIN_VREF 0x24 +#define PIN_OUT 0x40 +#define PIN_HP 0xc0 + static struct hda_verb alc880_init_verbs_three_stack[] = { + /* Set pin widgets for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + /* unmute capture amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* unmute capture1 amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* unmute capture2 amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute front mixer amp left (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute rear mixer amp left and right (volume = 0) */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute rear mixer amp left and right (volume = 0) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* set vol=0 front mixer amp */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute front-out pin widget amp (no gain on this amp) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 rear mixer amp */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* mute line-in pin widget amp left and right (no gain on this amp) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* set vol=0 clfe mixer amp */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* mute mic pin widget amp left and right (no gain on this amp) */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* using rear surround as the path for headphone output */ - /* unmute rear surround mixer amp left and right (volume = 0) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* set vol=0 rear surround mixer amp */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* PASD 3 stack boards use the Mic 2 as the headphone output */ /* need to program the selector associated with the Mic 2 pin widget to * surround path (index 0x01) for headphone output */ {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* need to retask the Mic 2 pin widget to output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer widget(nid=0x0B) * to support the input path of analog loopback @@ -688,14 +703,14 @@ static struct hda_verb alc880_init_verbs_three_stack[] = { * mic (mic 2) */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ - /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* mute CD */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + /* mute Mic 1 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* mute Line In 2 (for PASD boards Mic 2) */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* Unmute input amps for the line out paths to support the output path of * analog loopback @@ -704,66 +719,70 @@ static struct hda_verb alc880_init_verbs_three_stack[] = { */ /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute Surround (used as HP) out path */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute C/LFE out path */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute rear Surround out path */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, { } }; static struct hda_verb alc880_init_verbs_five_stack[] = { + /* Set pin widgets for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + /* mute capture amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* mute amp1 left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute front mixer amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* five rear and clfe */ - /* unmute rear mixer amp left and right (volume = 0) */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute clfe mixer amp left and right (volume = 0) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* set vol=0 front mixer amp */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute front-out pin widget amp (no gain on this amp) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 rear mixer amp */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute rear-out pin widget (no gain on this amp) */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 clfe mixer amp */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute clfe-pin widget amp (no gain on this amp) */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* using rear surround as the path for headphone output */ - /* unmute rear surround mixer amp left and right (volume = 0) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* set vol=0 rear surround mixer amp */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* PASD 3 stack boards use the Mic 2 as the headphone output */ /* need to program the selector associated with the Mic 2 pin widget to * surround path (index 0x01) for headphone output */ {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, /* mute pin widget amp left and right (no gain on this amp) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* need to retask the Mic 2 pin widget to output */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, @@ -773,13 +792,13 @@ static struct hda_verb alc880_init_verbs_five_stack[] = { /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* Unmute input amps for the line out paths to support the output path of * analog loopback @@ -788,123 +807,121 @@ static struct hda_verb alc880_init_verbs_five_stack[] = { */ /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute Surround (used as HP) out path */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute C/LFE out path */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute rear Surround out path */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, { } }; static struct hda_verb alc880_w810_init_verbs[] = { /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* front channel selector/amp: output 0: unmuted, max volume */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* front out pin: muted, (no volume selection) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* front out pin: NOT headphone enable, out enable, vref disabled */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* surround channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* surround channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* surround channel selector/amp: output 0: unmuted, max volume */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* surround out pin: muted, (no volume selection) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* surround out pin: NOT headphone enable, out enable, vref disabled */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* c/lfe channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* c/lfe channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* c/lfe channel selector/amp: output 0: unmuted, max volume */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* c/lfe out pin: muted, (no volume selection) */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* c/lfe out pin: NOT headphone enable, out enable, vref disabled */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* hphone/speaker input selector: front DAC */ {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* hphone/speaker out pin: muted, (no volume selection) */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* hphone/speaker out pin: NOT headphone enable, out enable, vref disabled */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, { } }; static struct hda_verb alc880_z71v_init_verbs[] = { - /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, - /* front channel selector/amp: output 0: unmuted, max volume */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* front out pin: muted, (no volume selection) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* front channel selector/amp: muted, DAC and mix (no vol) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* front channel selector/amp: output 0: vol=0 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* front out pin: unmuted, (no volume selection) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* front out pin: NOT headphone enable, out enable, vref disabled */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* headphone channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* headphone channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, - /* headphone channel selector/amp: output 0: unmuted, max volume */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* headphone out pin: muted, (no volume selection) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* headphone channel selector/amp: muted, DAC and mix (no vol) */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* headphone channel selector/amp: output 0: vol=0 */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* headphone out pin: muted, (no volume selection) */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* headpohne out pin: headphone enable, out enable, vref disabled */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer @@ -913,13 +930,13 @@ static struct hda_verb alc880_z71v_init_verbs[] = { /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, { } }; @@ -1284,10 +1301,14 @@ static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * } static snd_kcontrol_new_t alc880_test_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), - ALC_BIND_VOL("Surround Playback Volume", 0x0d, 2, HDA_OUTPUT), - ALC_BIND_VOL("CLFE Playback Volume", 0x0e, 2, HDA_OUTPUT), - ALC_BIND_VOL("Side Playback Volume", 0x0f, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + ALC_BIND_MUTE("CLFE Playback Volume", 0x0e, 2, HDA_INPUT), + ALC_BIND_MUTE("Side Playback Volume", 0x0f, 2, HDA_INPUT), PIN_CTL_TEST("Front Pin Mode", 0x14), PIN_CTL_TEST("Surround Pin Mode", 0x15), PIN_CTL_TEST("CLFE Pin Mode", 0x16), @@ -1310,10 +1331,10 @@ static snd_kcontrol_new_t alc880_test_mixer[] = { HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Source", @@ -1328,54 +1349,59 @@ static snd_kcontrol_new_t alc880_test_mixer[] = { .info = alc880_ch_mode_info, .get = alc880_ch_mode_get, .put = alc880_ch_mode_put, - .private_value = ARRAY_SIZE(alc880_test_modes), }, { } /* end */ }; static struct hda_verb alc880_test_init_verbs[] = { /* Unmute inputs of 0x0c - 0x0f */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* Vol output for 0x0c-0x0f */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* Set output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Unmute output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Set input pins 0x18-0x1c */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* vref 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mute input pins 0x18-0x1b */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* ADC set up */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Analog input/passthru */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, { } }; #endif @@ -1621,10 +1647,8 @@ static struct alc_channel_mode alc260_modes[1] = { }; snd_kcontrol_new_t alc260_base_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x08, 2, HDA_OUTPUT), - /* use LINE2 for the output */ - /* HDA_CODEC_MUTE("Front Playback Switch", 0x0f, 0x0, HDA_OUTPUT), */ - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), @@ -1635,10 +1659,10 @@ snd_kcontrol_new_t alc260_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), - ALC_BIND_VOL("Headphone Playback Volume", 0x09, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), - ALC_BIND_VOL_MONO("Mono Playback Volume", 0x0a, 1, 2, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), { @@ -1653,58 +1677,58 @@ snd_kcontrol_new_t alc260_base_mixer[] = { static struct hda_verb alc260_init_verbs[] = { /* Line In pin widget for input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* LINE-2 is used for line-out in rear */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* select line-out */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* LINE-OUT pin */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* enable HP */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* enable Mono */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* unmute amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to line in (default select for this ADC) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* unmute Line-Out mixer amp left and right (volume = 0) */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* unmute HP mixer amp left and right (volume = 0) */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* unmute Mono mixer amp left and right (volume = 0) */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* mute LINE-2 out */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* set vol=0 Line-Out mixer amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 HP mixer amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 Mono mixer amp left and right */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* unmute LINE-2 out pin */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ - /* unmute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* unmute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + /* mute CD */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* mute Line In */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + /* mute Mic */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* mute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* mute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* mute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, { } }; @@ -1828,16 +1852,16 @@ static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ static snd_kcontrol_new_t alc882_base_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Surround Playback Volume", 0x0d, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), - ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), - ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Side Playback Volume", 0x0f, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), @@ -1869,91 +1893,87 @@ static snd_kcontrol_new_t alc882_base_mixer[] = { static struct hda_verb alc882_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Front Pin: to output mode */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Front Pin: mute amp left and right (no volume) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* select Front mixer (0x0c, index 0) */ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Rear Pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Rear Pin: mute amp left and right (no volume) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* select Rear mixer (0x0d, index 1) */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE Pin */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* CLFE Pin: mute amp left and right (no volume) */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* select CLFE mixer (0x0e, index 2) */ {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Side Pin */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Side Pin: mute amp left and right (no volume) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* select Side mixer (0x0f, index 3) */ {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Headphone Pin */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Headphone Pin: mute amp left and right (no volume) */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* select Front mixer (0x0c, index 0) */ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Mic (rear) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Front Mic pin widget for input and vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* FIXME: use matrix-type input source selection */ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* ADC1: unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Unmute front loopback */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute rear loopback */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Mute CLFE loopback */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - /* Unmute side loopback */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, { } }; -- cgit v0.10.2 From 5ecd7022f52872db32eddf85a527064ed7b522a3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2005 19:54:23 +0200 Subject: [ALSA] hda-codec - Allow sub_device=0 in board config check HDA Codec driver Allow sub_device=0 in board config check. This means that every device with the given sub vendor ID will match. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8805928..f62d1d5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1540,7 +1540,8 @@ int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device); for (c = tbl; c->modelname || c->pci_subvendor; c++) { if (c->pci_subvendor == subsystem_vendor && - c->pci_subdevice == subsystem_device) + (! c->pci_subdevice /* all match */|| + (c->pci_subdevice == subsystem_device))) return c->config; } } -- cgit v0.10.2 From 16ded525389c31256bcc9fd44352ab799b60b7fc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2005 19:58:24 +0200 Subject: [ALSA] hda-codec - Add support of more models with ALC codecs HDA Codec driver,HDA Intel driver Merged the work of pshou for the support of more models with ALC codecs: ALC880 ASUS, Uniwill, FSC1734, generic 6-stack, and ALC260 HP. Tests with the real hardwares are appreciated. The codec patch is cleaned up: The preset configuration of codecs are stored in the table and copied to the spec instance. Added/fixed comments. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1b12035..5999156 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -75,6 +75,9 @@ enum { #define AC_VERB_GET_DIGI_CONVERT 0x0f0d #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f /* f10-f1a: GPIO */ +#define AC_VERB_GET_GPIO_DATA 0x0f15 +#define AC_VERB_GET_GPIO_MASK 0x0f16 +#define AC_VERB_GET_GPIO_DIRECTION 0x0f17 #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c /* @@ -97,6 +100,9 @@ enum { #define AC_VERB_SET_DIGI_CONVERT_1 0x70d #define AC_VERB_SET_DIGI_CONVERT_2 0x70e #define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f +#define AC_VERB_SET_GPIO_DATA 0x715 +#define AC_VERB_SET_GPIO_MASK 0x716 +#define AC_VERB_SET_GPIO_DIRECTION 0x717 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0d546ad..d898491 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1458,6 +1458,7 @@ static struct pci_device_id azx_ids[] = { { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */ { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */ + { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ULI */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 84ae90c..ce280c0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -33,7 +33,6 @@ /* ALC880 board config type */ enum { - ALC880_MINIMAL, ALC880_3ST, ALC880_3ST_DIG, ALC880_5ST, @@ -41,32 +40,54 @@ enum { ALC880_W810, ALC880_Z71V, ALC880_TEST, + ALC880_6ST_DIG, + ALC880_F1734, + ALC880_ASUS, + ALC880_ASUS_DIG, + ALC880_ASUS_W1V, + ALC880_UNIWILL_DIG, + ALC880_MODEL_LAST /* last tag */ +}; + +/* ALC260 models */ +enum { + ALC260_BASIC, + ALC260_HP, + ALC260_MODEL_LAST /* last tag */ }; struct alc_spec { /* codec parameterization */ - unsigned int front_panel: 1; - - snd_kcontrol_new_t* mixers[2]; + unsigned int front_panel: 1; /* indicates the board has a front panel; + * not referred currently for any purpose, + * though... + */ + + snd_kcontrol_new_t *mixers[2]; /* mixer arrays */ unsigned int num_mixers; - struct hda_verb *init_verbs; + struct hda_verb *init_verbs; /* initialization verbs + * don't forget NULL termination! + */ - char* stream_name_analog; + char *stream_name_analog; /* analog PCM stream */ struct hda_pcm_stream *stream_analog_playback; struct hda_pcm_stream *stream_analog_capture; - char* stream_name_digital; + char *stream_name_digital; /* digital PCM stream */ struct hda_pcm_stream *stream_digital_playback; struct hda_pcm_stream *stream_digital_capture; /* playback */ - struct hda_multi_out multiout; + struct hda_multi_out multiout; /* playback set-up + * max_channels, dacs must be set + * dig_out_nid and hp_nid are optional + */ /* capture */ unsigned int num_adc_nids; hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; + hda_nid_t dig_in_nid; /* digital-in NID; optional */ /* capture source */ const struct hda_input_mux *input_mux; @@ -77,9 +98,9 @@ struct alc_spec { int num_channel_mode; /* PCM information */ - struct hda_pcm pcm_rec[2]; + struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ - struct semaphore bind_mutex; + struct semaphore bind_mutex; /* for bound controls */ }; /* DAC/ADC assignment */ @@ -89,6 +110,11 @@ static hda_nid_t alc880_dac_nids[4] = { 0x02, 0x05, 0x04, 0x03 }; +static hda_nid_t alc880_6st_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x03, 0x04, 0x05 +}; + static hda_nid_t alc880_w810_dac_nids[3] = { /* front, rear/surround, clfe */ 0x02, 0x03, 0x04 @@ -122,9 +148,14 @@ static hda_nid_t alc260_dac_nids[1] = { 0x02, }; -static hda_nid_t alc260_adc_nids[2] = { - /* ADC0-1 */ - 0x04, 0x05, +static hda_nid_t alc260_adc_nids[1] = { + /* ADC0 */ + 0x04, +}; + +static hda_nid_t alc260_hp_adc_nids[1] = { + /* ADC1 */ + 0x05, }; #define ALC260_DIGOUT_NID 0x03 @@ -140,6 +171,17 @@ static struct hda_input_mux alc880_capture_source = { }, }; +//pshou 05/24/05 +static struct hda_input_mux alc880_6stack_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + static struct hda_input_mux alc260_capture_source = { .num_items = 4, .items = { @@ -307,6 +349,11 @@ static struct alc_channel_mode alc880_z71v_modes[1] = { { 2, NULL } }; +//pshou 05/19/05 +static struct alc_channel_mode alc880_sixstack_modes[1] = { + { 8, NULL }, +}; + /* */ static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -605,6 +652,172 @@ static snd_kcontrol_new_t alc880_z71v_mixer[] = { { } /* end */ }; +//pshou 05/24/05 +static snd_kcontrol_new_t alc880_six_stack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), */ + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc880_ch_mode_info, + .get = alc880_ch_mode_get, + .put = alc880_ch_mode_put, + }, + { } /* end */ +}; + +// 03/08/05 Fujitsu +static snd_kcontrol_new_t alc880_2_jack_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + +//pshou 04/24/05 +static snd_kcontrol_new_t alc880_asus_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc880_ch_mode_info, + .get = alc880_ch_mode_get, + .put = alc880_ch_mode_put, + }, + { } /* end */ +}; + +// pshou 05/03/05 +static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc880_ch_mode_info, + .get = alc880_ch_mode_get, + .put = alc880_ch_mode_put, + }, + { } /* end */ +}; /* */ static int alc_build_controls(struct hda_codec *codec) @@ -642,7 +855,8 @@ static int alc_build_controls(struct hda_codec *codec) #define AMP_OUT_UNMUTE 0xb000 #define AMP_OUT_ZERO 0xb000 #define PIN_IN 0x20 -#define PIN_VREF 0x24 +#define PIN_VREF80 0x24 +#define PIN_VREF50 0x21 #define PIN_OUT 0x40 #define PIN_HP 0xc0 @@ -657,19 +871,19 @@ static struct hda_verb alc880_init_verbs_three_stack[] = { /* CD pin widget for input */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* unmute capture amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute capture1 amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute capture2 amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set vol=0 front mixer amp */ @@ -704,11 +918,11 @@ static struct hda_verb alc880_init_verbs_three_stack[] = { */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ /* mute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, /* mute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* mute Line In 2 (for PASD boards Mic 2) */ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, @@ -745,19 +959,19 @@ static struct hda_verb alc880_init_verbs_five_stack[] = { /* CD pin widget for input */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* mute capture amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* mute amp1 left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set vol=0 front mixer amp */ @@ -792,13 +1006,13 @@ static struct hda_verb alc880_init_verbs_five_stack[] = { /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, /* Unmute input amps for the line out paths to support the output path of * analog loopback @@ -909,19 +1123,19 @@ static struct hda_verb alc880_z71v_init_verbs[] = { /* CD pin widget for input */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer @@ -930,17 +1144,150 @@ static struct hda_verb alc880_z71v_init_verbs[] = { /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + + { } +}; + +//pshou 05/24/05 +static struct hda_verb alc880_six_stack_init_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* unmute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer + * widget(nid=0x0B) to support the input path of analog loopback + */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + /* unmute Line In */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + /* unmute Mic 1 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* unmute Mic 2 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Front out path */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Unmute Surround (used as HP) out path */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Unmute C/LFE out path */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mute */ + /* Unmute rear Surround out path */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +static struct hda_verb alc880_2_jack_init_verbs[] = { + /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x0C, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1B, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, { } }; +static struct hda_verb alc880_asus_init_verbs[] = { + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ + /* unmute CD */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + /* unmute Line In */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + /* unmute Mic 1 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* unmute Line In 2 (for PASD boards Mic 2) */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* Unmute Front out path */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Unmute Surround (used as HP) out path */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Unmute C/LFE out path */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + { } +}; + + static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1379,8 +1726,8 @@ static struct hda_verb alc880_test_init_verbs[] = { {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Set input pins 0x18-0x1c */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -1447,6 +1794,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { /* Back 3 jack, front 2 jack (Internal add Aux-In) */ { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, + { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST }, /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, @@ -1463,6 +1811,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST }, { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST }, { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST }, /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, @@ -1474,6 +1823,10 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG }, { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, { .modelname = "w810", .config = ALC880_W810 }, { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 }, @@ -1481,6 +1834,30 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .modelname = "z71v", .config = ALC880_Z71V }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, + { .modelname = "6statack-digout", .config = ALC880_6ST_DIG }, + { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG }, + { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, + { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, + + { .modelname = "asua", .config = ALC880_ASUS }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, + + { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, + { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, + + { .modelname = "F1734", .config = ALC880_F1734 }, + { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, + #ifdef CONFIG_SND_DEBUG { .modelname = "test", .config = ALC880_TEST }, #endif @@ -1488,10 +1865,207 @@ static struct hda_board_config alc880_cfg_tbl[] = { {} }; +/* + * configuration template - to be copied to the spec instance + */ +struct alc_config_preset { + snd_kcontrol_new_t *mixers; + unsigned int front_panel: 1; /* optional */ + unsigned int gpio_payload; /* optional */ + struct hda_verb *init_verbs; + unsigned int num_dacs; + hda_nid_t *dac_nids; + hda_nid_t dig_out_nid; /* optional */ + hda_nid_t hp_nid; /* optional */ + unsigned int num_adc_nids; + hda_nid_t *adc_nids; + unsigned int num_channel_mode; + const struct alc_channel_mode *channel_mode; + const struct hda_input_mux *input_mux; +}; + +static struct alc_config_preset alc880_presets[] = { + [ALC880_3ST] = { + .mixers = alc880_base_mixer, + .init_verbs = alc880_init_verbs_three_stack, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .front_panel = 1, + .dac_nids = alc880_dac_nids, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_3ST_DIG] = { + .mixers = alc880_base_mixer, + .init_verbs = alc880_init_verbs_three_stack, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .front_panel = 1, + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_5ST] = { + .mixers = alc880_five_stack_mixer, + .init_verbs = alc880_init_verbs_five_stack, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), + .channel_mode = alc880_fivestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_5ST_DIG] = { + .mixers = alc880_five_stack_mixer, + .init_verbs = alc880_init_verbs_five_stack, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), + .channel_mode = alc880_fivestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_6ST_DIG] = { + .mixers = alc880_six_stack_mixer, + .init_verbs = alc880_six_stack_init_verbs, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), + .dac_nids = alc880_6st_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), + .channel_mode = alc880_sixstack_modes, + .input_mux = &alc880_6stack_capture_source, + }, + [ALC880_W810] = { + .mixers = alc880_w810_base_mixer, + .init_verbs = alc880_w810_init_verbs, + .gpio_payload = 0x2, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + // No dedicated headphone socket - it's shared with built-in speakers. + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), + .channel_mode = alc880_w810_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_Z71V] = { + .mixers = alc880_z71v_mixer, + .init_verbs = alc880_z71v_init_verbs, + .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), + .dac_nids = alc880_z71v_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_z71v_modes), + .channel_mode = alc880_z71v_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_F1734] = { + .mixers = alc880_2_jack_mixer, + .init_verbs = alc880_2_jack_init_verbs, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_z71v_modes), + .channel_mode = alc880_z71v_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS] = { + .mixers = alc880_asus_mixer, + .init_verbs = alc880_asus_init_verbs, + .gpio_payload = 0x1, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_DIG] = { + .mixers = alc880_asus_mixer, + .init_verbs = alc880_asus_init_verbs, + .gpio_payload = 0x1, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_W1V] = { + .mixers = alc880_asus_w1v_mixer, + .init_verbs = alc880_asus_init_verbs, + .gpio_payload = 0x1, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_UNIWILL_DIG] = { + .mixers = alc880_asus_mixer, + .init_verbs = alc880_asus_init_verbs, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, +#ifdef CONFIG_SND_DEBUG + [ALC880_TEST] = { + .mixers = alc880_test_mixer, + .init_verbs = alc880_test_init_verbs, + .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), + .dac_nids = alc880_test_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_test_modes), + .channel_mode = alc880_test_modes, + .input_mux = &alc880_test_capture_source, + }, +#endif +}; + static int patch_alc880(struct hda_codec *codec) { struct alc_spec *spec; int board_config; + const struct alc_config_preset *preset; spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -1501,91 +2075,31 @@ static int patch_alc880(struct hda_codec *codec) codec->spec = spec; board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); - if (board_config < 0) { + if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { snd_printd(KERN_INFO "hda_codec: Unknown model for ALC880\n"); - board_config = ALC880_MINIMAL; + board_config = ALC880_3ST; } + preset = &alc880_presets[board_config]; - switch (board_config) { - case ALC880_W810: - spec->mixers[spec->num_mixers] = alc880_w810_base_mixer; - spec->num_mixers++; - break; - case ALC880_5ST: - case ALC880_5ST_DIG: - spec->mixers[spec->num_mixers] = alc880_five_stack_mixer; - spec->num_mixers++; - break; - case ALC880_Z71V: - spec->mixers[spec->num_mixers] = alc880_z71v_mixer; - spec->num_mixers++; - break; -#ifdef CONFIG_SND_DEBUG - case ALC880_TEST: - spec->mixers[spec->num_mixers] = alc880_test_mixer; - spec->num_mixers++; - break; -#endif - default: - spec->mixers[spec->num_mixers] = alc880_base_mixer; - spec->num_mixers++; - break; - } - - switch (board_config) { - case ALC880_3ST_DIG: - case ALC880_5ST_DIG: - case ALC880_W810: - case ALC880_Z71V: - case ALC880_TEST: - spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; - break; - default: - break; - } + spec->mixers[spec->num_mixers] = preset->mixers; + snd_assert(spec->mixers[0], kfree(spec);return -EINVAL); + spec->num_mixers++; - switch (board_config) { - case ALC880_3ST: - case ALC880_3ST_DIG: - case ALC880_5ST: - case ALC880_5ST_DIG: - case ALC880_W810: - spec->front_panel = 1; - break; - default: - break; + /* some MBs need GPIO setup */ + if (preset->gpio_payload) { + /* Enable mask and set output */ + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, preset->gpio_payload); + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, preset->gpio_payload); + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, preset->gpio_payload); } - switch (board_config) { - case ALC880_5ST: - case ALC880_5ST_DIG: - spec->init_verbs = alc880_init_verbs_five_stack; - spec->channel_mode = alc880_fivestack_modes; - spec->num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes); - break; - case ALC880_W810: - spec->init_verbs = alc880_w810_init_verbs; - spec->channel_mode = alc880_w810_modes; - spec->num_channel_mode = ARRAY_SIZE(alc880_w810_modes); - break; - case ALC880_Z71V: - spec->init_verbs = alc880_z71v_init_verbs; - spec->channel_mode = alc880_z71v_modes; - spec->num_channel_mode = ARRAY_SIZE(alc880_z71v_modes); - break; -#ifdef CONFIG_SND_DEBUG - case ALC880_TEST: - spec->init_verbs = alc880_test_init_verbs; - spec->channel_mode = alc880_test_modes; - spec->num_channel_mode = ARRAY_SIZE(alc880_test_modes); - break; -#endif - default: - spec->init_verbs = alc880_init_verbs_three_stack; - spec->channel_mode = alc880_threestack_modes; - spec->num_channel_mode = ARRAY_SIZE(alc880_threestack_modes); - break; - } + spec->front_panel = preset->front_panel; + spec->init_verbs = preset->init_verbs; + spec->channel_mode = preset->channel_mode; + spec->num_channel_mode = preset->num_channel_mode; spec->stream_name_analog = "ALC880 Analog"; spec->stream_analog_playback = &alc880_pcm_analog_playback; @@ -1597,35 +2111,14 @@ static int patch_alc880(struct hda_codec *codec) spec->multiout.max_channels = spec->channel_mode[0].channels; - switch (board_config) { - case ALC880_W810: - spec->multiout.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids); - spec->multiout.dac_nids = alc880_w810_dac_nids; - // No dedicated headphone socket - it's shared with built-in speakers. - break; - case ALC880_Z71V: - spec->multiout.num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids); - spec->multiout.dac_nids = alc880_z71v_dac_nids; - spec->multiout.hp_nid = 0x03; - break; -#ifdef CONFIG_SND_DEBUG - case ALC880_TEST: - spec->multiout.num_dacs = ARRAY_SIZE(alc880_test_dac_nids); - spec->multiout.dac_nids = alc880_test_dac_nids; - spec->input_mux = &alc880_test_capture_source; - break; -#endif - default: - spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids); - spec->multiout.dac_nids = alc880_dac_nids; - spec->multiout.hp_nid = 0x03; /* rear-surround NID */ - break; - } + spec->multiout.num_dacs = preset->num_dacs; + spec->multiout.dac_nids = preset->adc_nids; + spec->multiout.dig_out_nid = preset->dig_out_nid; + spec->multiout.hp_nid = preset->hp_nid; - if (! spec->input_mux) - spec->input_mux = &alc880_capture_source; - spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); - spec->adc_nids = alc880_adc_nids; + spec->input_mux = preset->input_mux; + spec->num_adc_nids = preset->num_adc_nids; + spec->adc_nids = preset->adc_nids; codec->patch_ops = alc_patch_ops; @@ -1675,15 +2168,42 @@ snd_kcontrol_new_t alc260_base_mixer[] = { { } /* end */ }; +snd_kcontrol_new_t alc260_hp_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + static struct hda_verb alc260_init_verbs[] = { /* Line In pin widget for input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* LINE-2 is used for line-out in rear */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* select line-out */ @@ -1695,9 +2215,13 @@ static struct hda_verb alc260_init_verbs[] = { /* enable Mono */ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to line in (default select for this ADC) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* mute capture amp left and right */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* set connection select to line in (default select for this ADC) */ + {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, /* set vol=0 Line-Out mixer amp left and right */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* unmute pin widget amp left and right (no gain on this amp) */ @@ -1714,11 +2238,11 @@ static struct hda_verb alc260_init_verbs[] = { {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ /* mute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* mute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, /* mute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* mute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -1746,9 +2270,16 @@ static struct hda_pcm_stream alc260_pcm_analog_capture = { .nid = 0x4, }; +static struct hda_board_config alc260_cfg_tbl[] = { + { .modelname = "hp", .config = ALC260_HP }, + { .pci_subvendor = 0x103c, .config = ALC260_HP }, + {} +}; + static int patch_alc260(struct hda_codec *codec) { struct alc_spec *spec; + int board_config; spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -1757,8 +2288,22 @@ static int patch_alc260(struct hda_codec *codec) init_MUTEX(&spec->bind_mutex); codec->spec = spec; - spec->mixers[spec->num_mixers] = alc260_base_mixer; - spec->num_mixers++; + board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); + if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { + snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n"); + board_config = ALC260_BASIC; + } + + switch (board_config) { + case ALC260_HP: + spec->mixers[spec->num_mixers] = alc260_base_mixer; + spec->num_mixers++; + break; + default: + spec->mixers[spec->num_mixers] = alc260_base_mixer; + spec->num_mixers++; + break; + } spec->init_verbs = alc260_init_verbs; spec->channel_mode = alc260_modes; @@ -1773,8 +2318,17 @@ static int patch_alc260(struct hda_codec *codec) spec->multiout.dac_nids = alc260_dac_nids; spec->input_mux = &alc260_capture_source; - spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); - spec->adc_nids = alc260_adc_nids; + switch (board_config) { + case ALC260_HP: + spec->stream_analog_capture->nid = 5; + spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); + spec->adc_nids = alc260_hp_adc_nids; + break; + default: + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); + spec->adc_nids = alc260_adc_nids; + break; + } codec->patch_ops = alc_patch_ops; @@ -1940,9 +2494,9 @@ static struct hda_verb alc882_init_verbs[] = { /* select Front mixer (0x0c, index 0) */ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Mic (rear) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Front Mic pin widget for input and vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Line In pin widget for input */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ -- cgit v0.10.2 From b636a71d9b9525ee51ca872d461817a5bd5c39fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 13 Jun 2005 14:13:09 +0200 Subject: [ALSA] Add const prefix Control Midlevel Add const prefix to snd_kcontrol_new_t pointer for better protection. Signed-off-by: Takashi Iwai diff --git a/include/sound/control.h b/include/sound/control.h index 7b9444c..ef7903c 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -106,7 +106,7 @@ typedef int (*snd_kctl_ioctl_func_t) (snd_card_t * card, void snd_ctl_notify(snd_card_t * card, unsigned int mask, snd_ctl_elem_id_t * id); snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * kcontrol, unsigned int access); -snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * kcontrolnew, void * private_data); +snd_kcontrol_t *snd_ctl_new1(const snd_kcontrol_new_t * kcontrolnew, void * private_data); void snd_ctl_free_one(snd_kcontrol_t * kcontrol); int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol); int snd_ctl_remove(snd_card_t * card, snd_kcontrol_t * kcontrol); diff --git a/sound/core/control.c b/sound/core/control.c index 4e39a21..227f3cf 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -215,7 +215,7 @@ snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * control, unsigned int access) * * Returns the pointer of the newly generated instance, or NULL on failure. */ -snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * ncontrol, void *private_data) +snd_kcontrol_t *snd_ctl_new1(const snd_kcontrol_new_t * ncontrol, void *private_data) { snd_kcontrol_t kctl; unsigned int access; -- cgit v0.10.2 From e9edcee061a80181f0d6e7cada07e1898c14718e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 13 Jun 2005 14:16:38 +0200 Subject: [ALSA] hda-codec - More fix of ALC880 codec support Documentation,HDA Codec driver,HDA generic driver,HDA Intel driver - Fix some invalid configurations, typos in the last patch - Make init_verbs chainable, so that different configs can share the same init_verbs - Reorder and clean up the source codes in patch_realtek.c - Add the pin default configuration parser, used commonly in cmedia and realtek patch codes. - Add 'auto' model to ALC880 for auto-configuration from BIOS Use this model as default, and 3-stack as fallback Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index ced9a6e..104a994 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -638,6 +638,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out w810 3-jack z71v 3-jack (HP shared SPDIF) + asus 3-jack + uniwill 3-jack + F1734 2-jack CMI9880 minimal 3-jack in back @@ -645,6 +648,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. full 6-jack in back, 2-jack in front full_dig 6-jack in back, 2-jack in front, SPDIF I/O allout 5-jack in back, 2-jack in front, SPDIF out + auto auto-config reading BIOS (default) Note 2: If you get click noises on output, try the module option position_fix=1 or 2. position_fix=1 will use the SD_LPIB diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f62d1d5..e2cf023 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1520,9 +1520,9 @@ int snd_hda_build_pcms(struct hda_bus *bus) * * If no entries are matching, the function returns a negative value. */ -int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl) +int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl) { - struct hda_board_config *c; + const struct hda_board_config *c; if (codec->bus->modelname) { for (c = tbl; c->modelname || c->pci_subvendor; c++) { @@ -1714,6 +1714,105 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_o return 0; } +/* + * Helper for automatic ping configuration + */ +/* parse all pin widgets and store the useful pin nids to cfg */ +int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg) +{ + hda_nid_t nid, nid_start; + int i, j, nodes; + short seq, sequences[4], assoc_line_out; + + memset(cfg, 0, sizeof(*cfg)); + + memset(sequences, 0, sizeof(sequences)); + assoc_line_out = 0; + + nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); + for (nid = nid_start; nid < nodes + nid_start; nid++) { + unsigned int wid_caps = snd_hda_param_read(codec, nid, + AC_PAR_AUDIO_WIDGET_CAP); + unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + unsigned int def_conf; + short assoc, loc; + + /* read all default configuration for pin complex */ + if (wid_type != AC_WID_PIN) + continue; + def_conf = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) + continue; + loc = get_defcfg_location(def_conf); + switch (get_defcfg_device(def_conf)) { + case AC_JACK_LINE_OUT: + case AC_JACK_SPEAKER: + seq = get_defcfg_sequence(def_conf); + assoc = get_defcfg_association(def_conf); + if (! assoc) + continue; + if (! assoc_line_out) + assoc_line_out = assoc; + else if (assoc_line_out != assoc) + continue; + if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) + continue; + cfg->line_out_pins[cfg->line_outs] = nid; + sequences[cfg->line_outs] = seq; + cfg->line_outs++; + break; + case AC_JACK_HP_OUT: + cfg->hp_pin = nid; + break; + case AC_JACK_MIC_IN: + if (loc == AC_JACK_LOC_FRONT) + cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid; + else + cfg->input_pins[AUTO_PIN_MIC] = nid; + break; + case AC_JACK_LINE_IN: + if (loc == AC_JACK_LOC_FRONT) + cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid; + else + cfg->input_pins[AUTO_PIN_LINE] = nid; + break; + case AC_JACK_CD: + cfg->input_pins[AUTO_PIN_CD] = nid; + break; + case AC_JACK_AUX: + cfg->input_pins[AUTO_PIN_AUX] = nid; + break; + case AC_JACK_SPDIF_OUT: + cfg->dig_out_pin = nid; + break; + case AC_JACK_SPDIF_IN: + cfg->dig_in_pin = nid; + break; + } + } + + /* sort by sequence */ + for (i = 0; i < cfg->line_outs; i++) + for (j = i + 1; j < cfg->line_outs; j++) + if (sequences[i] > sequences[j]) { + seq = sequences[i]; + sequences[i] = sequences[j]; + sequences[j] = seq; + nid = cfg->line_out_pins[i]; + cfg->line_out_pins[i] = cfg->line_out_pins[j]; + cfg->line_out_pins[j] = nid; + } + + /* Swap surround and CLFE: the association order is front/CLFE/surr/back */ + if (cfg->line_outs >= 3) { + nid = cfg->line_out_pins[1]; + cfg->line_out_pins[1] = cfg->line_out_pins[2]; + cfg->line_out_pins[2] = nid; + } + + return 0; +} + #ifdef CONFIG_PM /* * power management diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index bfbeff2..2d046ab 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -68,8 +68,8 @@ struct hda_gspec { /* * retrieve the default device type from the default config value */ -#define get_defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) -#define get_defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) +#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) +#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) /* * destructor @@ -323,7 +323,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, if (! (node->pin_caps & AC_PINCAP_OUT)) continue; if (jack_type >= 0) { - if (jack_type != get_defcfg_type(node)) + if (jack_type != defcfg_type(node)) continue; if (node->wid_caps & AC_WCAP_DIGITAL) continue; /* skip SPDIF */ @@ -418,8 +418,8 @@ static int capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc */ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) { - unsigned int location = get_defcfg_location(node); - switch (get_defcfg_type(node)) { + unsigned int location = defcfg_location(node); + switch (defcfg_type(node)) { case AC_JACK_LINE_IN: if ((location & 0x0f) == AC_JACK_LOC_FRONT) return "Front Line"; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d898491..5e0cca3 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1458,7 +1458,7 @@ static struct pci_device_id azx_ids[] = { { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */ { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */ - { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ULI */ + { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ALI 5461? */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index b8fbbc4..810cfd2 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -130,7 +130,7 @@ struct hda_board_config { unsigned short pci_subdevice; }; -int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl); +int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew); /* @@ -158,4 +158,35 @@ struct hda_bus_unsolicited { struct work_struct work; }; +/* + * Helper for automatic ping configuration + */ + +enum { + AUTO_PIN_MIC, + AUTO_PIN_FRONT_MIC, + AUTO_PIN_LINE, + AUTO_PIN_FRONT_LINE, + AUTO_PIN_CD, + AUTO_PIN_AUX, + AUTO_PIN_LAST +}; + +struct auto_pin_cfg { + int line_outs; + hda_nid_t line_out_pins[4]; /* sorted in the order of Front/Surr/CLFE/Side */ + hda_nid_t hp_pin; + hda_nid_t input_pins[AUTO_PIN_LAST]; + hda_nid_t dig_out_pin; + hda_nid_t dig_in_pin; +}; + +#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) +#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) +#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) +#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) +#define get_defcfg_device(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) + +int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg); + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 087230c..2d6e3e3 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -51,6 +51,7 @@ struct cmi_spec { /* playback */ struct hda_multi_out multiout; hda_nid_t dac_nids[4]; /* NID for each DAC */ + int num_dacs; /* capture */ hda_nid_t *adc_nids; @@ -77,6 +78,19 @@ struct cmi_spec { struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ }; +/* amp values */ +#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) +#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 +/* pinctl values */ +#define PIN_IN 0x20 +#define PIN_VREF80 0x24 +#define PIN_VREF50 0x21 +#define PIN_OUT 0x40 +#define PIN_HP 0xc0 + /* * input MUX */ @@ -114,9 +128,9 @@ static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon /* 3-stack / 2 channel */ static struct hda_verb cmi9880_ch2_init[] = { /* set line-in PIN for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* set mic PIN for input, also enable vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* route front PCM (DAC1) to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, {} @@ -125,9 +139,9 @@ static struct hda_verb cmi9880_ch2_init[] = { /* 3-stack / 6 channel */ static struct hda_verb cmi9880_ch6_init[] = { /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* route front PCM (DAC1) to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, {} @@ -136,9 +150,9 @@ static struct hda_verb cmi9880_ch6_init[] = { /* 3-stack+front / 8 channel */ static struct hda_verb cmi9880_ch8_init[] = { /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* route rear-surround PCM (DAC4) to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, {} @@ -281,27 +295,27 @@ static hda_nid_t cmi9880_adc_nids[2] = { */ static struct hda_verb cmi9880_basic_init[] = { /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* route front PCM to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* route front mic to ADC1/2 */ { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, @@ -310,27 +324,27 @@ static struct hda_verb cmi9880_basic_init[] = { static struct hda_verb cmi9880_allout_init[] = { /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* route front PCM to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, /* port-A for side (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, /* port-C for surround (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* route front mic to ADC1/2 */ { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, @@ -365,101 +379,9 @@ static int cmi9880_build_controls(struct hda_codec *codec) return 0; } -#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) -#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) -#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) - -/* get all pin default configuration in def_conf */ -static int cmi9880_get_pin_def_config(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - hda_nid_t nid, nid_start; - int i = 0, nodes; - - nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); - for (nid = nid_start; nid < nodes + nid_start; nid++) { - unsigned int wid_caps = snd_hda_param_read(codec, nid, - AC_PAR_AUDIO_WIDGET_CAP); - unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - /* read all default configuration for pin complex */ - if (wid_type == AC_WID_PIN) { - spec->pin_nid[i] = nid; - spec->def_conf[i] = - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); - i++; - } - } - spec->pin_def_confs = i; - return 0; -} - -/* get a pin default configuration of nid in def_conf */ -static unsigned int cmi9880_get_def_config(struct hda_codec *codec, hda_nid_t nid) -{ - struct cmi_spec *spec = codec->spec; - int i = 0; - - while (spec->pin_nid[i] != nid && i < spec->pin_def_confs) - i++; - if (i == spec->pin_def_confs) - return (unsigned int) -1; - else - return spec->def_conf[i]; -} - -/* decide what pins to use for multichannel playback */ -static int cmi9880_get_multich_pins(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - int i, j, pins, seq[4]; - int max_channel = 0; - unsigned int def_conf, sequence; - hda_nid_t nid; - - memset(spec->multich_pin, 0, sizeof(spec->multich_pin)); - for (pins = 0, i = 0; i < spec->pin_def_confs && pins < 4; i++) { - def_conf = spec->def_conf[i]; - /* skip pin not connected */ - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - continue; - /* get the sequence if association == 1 */ - /* the other pins have association = 0, incorrect in spec 1.0 */ - if (get_defcfg_association(def_conf) == 1) { - sequence = get_defcfg_sequence(def_conf); - seq[pins] = sequence; - spec->multich_pin[pins] = spec->pin_nid[i]; - pins++; // ready for next slot - max_channel += 2; - } - } - /* sort by sequence, data collected here will be for Windows */ - for (i = 0; i < pins; i++) { - for (j = i + 1; j < pins; j++) { - if (seq[j] < seq[i]) { - sequence = seq[j]; - nid = spec->multich_pin[j]; - seq[j] = seq[i]; - spec->multich_pin[j] = spec->multich_pin[i]; - seq[i] = sequence; - spec->multich_pin[i] = nid; - } - } - } - /* the pin assignment is for front, C/LFE, surround and back */ - if (max_channel >= 6) { - hda_nid_t temp; - /* exchange pin of C/LFE and surround */ - temp = spec->multich_pin[1]; - spec->multich_pin[1] = spec->multich_pin[2]; - spec->multich_pin[2] = temp; - } - return max_channel; -} - /* fill in the multi_dac_nids table, which will decide which audio widget to use for each channel */ -static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) +static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct cmi_spec *spec = codec->spec; hda_nid_t nid; @@ -470,32 +392,34 @@ static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); memset(assigned, 0, sizeof(assigned)); /* check the pins we found */ - for (i = 0; i < spec->multiout.max_channels / 2; i++) { - nid = spec->multich_pin[i]; + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ - if (nid <= 0x0e && nid >= 0x0b) { - spec->dac_nids[i] = nid - 0x08; + if (nid >= 0x0b && nid <= 0x0e) { + spec->dac_nids[i] = (nid - 0x0b) + 0x03; assigned[nid - 0x0b] = 1; } } /* left pin can be connect to any audio widget */ - for (i = 0; i < spec->multiout.max_channels / 2; i++) { - if (!assigned[i]) { - /* search for an empty channel */ - /* I should also check the pin type */ - for (j = 0; j < ARRAY_SIZE(spec->dac_nids); j++) - if (! spec->dac_nids[j]) { - spec->dac_nids[j] = i + 3; - assigned[i] = 1; - break; - } + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (nid <= 0x0e) + continue; + /* search for an empty channel */ + for (j = 0; j < cfg->line_outs; j++) { + if (! assigned[j]) { + spec->dac_nids[i] = i + 0x03; + assigned[j] = 1; + break; + } } } + spec->num_dacs = cfg->line_outs; return 0; } /* create multi_init table, which is used for multichannel initialization */ -static int cmi9880_fill_multi_init(struct hda_codec *codec) +static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct cmi_spec *spec = codec->spec; hda_nid_t nid; @@ -503,29 +427,26 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec) /* clear the table, only one c-media dac assumed here */ memset(spec->multi_init, 0, sizeof(spec->multi_init)); - for (j = 0, i = 0; i < spec->multiout.max_channels / 2; i++) { + for (j = 0, i = 0; i < cfg->line_outs; i++) { hda_nid_t conn[4]; - nid = spec->multich_pin[i]; + nid = cfg->line_out_pins[i]; /* set as output */ spec->multi_init[j].nid = nid; spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; - spec->multi_init[j].param = 0xc0; + spec->multi_init[j].param = PIN_OUT; j++; - /* nid 0x0f,0x10,0x1f,0x20 are needed to set connection */ - switch (nid) { - case 0x0f: - case 0x10: - case 0x1f: - case 0x20: + if (nid > 0x0e) { /* set connection */ spec->multi_init[j].nid = nid; spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; + spec->multi_init[j].param = 0; /* find the index in connect list */ len = snd_hda_get_connections(codec, nid, conn, 4); for (k = 0; k < len; k++) - if (conn[k] == spec->dac_nids[i]) + if (conn[k] == spec->dac_nids[i]) { + spec->multi_init[j].param = j; break; - spec->multi_init[j].param = k < len ? k : 0; + } j++; break; } @@ -759,6 +680,7 @@ static int patch_cmi9880(struct hda_codec *codec) /* copy default DAC NIDs */ memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); + spec->num_dacs = 4; switch (spec->board_config) { case CMI_MINIMAL: @@ -795,18 +717,16 @@ static int patch_cmi9880(struct hda_codec *codec) { unsigned int port_e, port_f, port_g, port_h; unsigned int port_spdifi, port_spdifo; - int max_channels; + struct auto_pin_cfg cfg; + /* collect pin default configuration */ - cmi9880_get_pin_def_config(codec); - port_e = cmi9880_get_def_config(codec, 0x0f); - port_f = cmi9880_get_def_config(codec, 0x10); - port_g = cmi9880_get_def_config(codec, 0x1f); - port_h = cmi9880_get_def_config(codec, 0x20); - port_spdifi = cmi9880_get_def_config(codec, 0x13); - port_spdifo = cmi9880_get_def_config(codec, 0x12); + port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); spec->front_panel = 1; if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { + port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); spec->surr_switch = 1; /* no front panel */ if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || @@ -824,24 +744,26 @@ static int patch_cmi9880(struct hda_codec *codec) spec->multiout.max_channels = cmi9880_channel_modes[0].channels; } else { spec->input_mux = &cmi9880_basic_mux; + port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) spec->dig_in_nid = CMI_DIG_IN_NID; spec->multiout.max_channels = 8; } - max_channels = cmi9880_get_multich_pins(codec); - if (max_channels > 0) { - spec->multiout.max_channels = max_channels; - cmi9880_fill_multi_dac_nids(codec); - cmi9880_fill_multi_init(codec); + snd_hda_parse_pin_def_config(codec, &cfg); + if (cfg.line_outs) { + spec->multiout.max_channels = cfg.line_outs * 2; + cmi9880_fill_multi_dac_nids(codec, &cfg); + cmi9880_fill_multi_init(codec, &cfg); } else snd_printd("patch_cmedia: cannot detect association in defcfg\n"); break; } } - spec->multiout.num_dacs = 4; + spec->multiout.num_dacs = spec->num_dacs; spec->multiout.dac_nids = spec->dac_nids; spec->adc_nids = cmi9880_adc_nids; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ce280c0..9edd558 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -39,13 +39,16 @@ enum { ALC880_5ST_DIG, ALC880_W810, ALC880_Z71V, - ALC880_TEST, + ALC880_AUTO, ALC880_6ST_DIG, ALC880_F1734, ALC880_ASUS, ALC880_ASUS_DIG, ALC880_ASUS_W1V, ALC880_UNIWILL_DIG, +#ifdef CONFIG_SND_DEBUG + ALC880_TEST, +#endif ALC880_MODEL_LAST /* last tag */ }; @@ -56,19 +59,28 @@ enum { ALC260_MODEL_LAST /* last tag */ }; +/* amp values */ +#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) +#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 +/* pinctl values */ +#define PIN_IN 0x20 +#define PIN_VREF80 0x24 +#define PIN_VREF50 0x21 +#define PIN_OUT 0x40 +#define PIN_HP 0xc0 + struct alc_spec { /* codec parameterization */ - unsigned int front_panel: 1; /* indicates the board has a front panel; - * not referred currently for any purpose, - * though... - */ - - snd_kcontrol_new_t *mixers[2]; /* mixer arrays */ + snd_kcontrol_new_t *mixers[3]; /* mixer arrays */ unsigned int num_mixers; - struct hda_verb *init_verbs; /* initialization verbs - * don't forget NULL termination! - */ + const struct hda_verb *init_verbs[3]; /* initialization verbs + * don't forget NULL termination! + */ + unsigned int num_init_verbs; char *stream_name_analog; /* analog PCM stream */ struct hda_pcm_stream *stream_analog_playback; @@ -101,96 +113,14 @@ struct alc_spec { struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ struct semaphore bind_mutex; /* for bound controls */ -}; - -/* DAC/ADC assignment */ - -static hda_nid_t alc880_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x05, 0x04, 0x03 -}; - -static hda_nid_t alc880_6st_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -static hda_nid_t alc880_w810_dac_nids[3] = { - /* front, rear/surround, clfe */ - 0x02, 0x03, 0x04 -}; - -static hda_nid_t alc880_z71v_dac_nids[1] = { - /* front only? */ - 0x02 -}; - -#if 0 -/* The datasheet says the node 0x07 is connected from inputs, - * but it shows zero connection in the real implementation on some devices. - */ -static hda_nid_t alc880_adc_nids[3] = { - /* ADC0-2 */ - 0x07, 0x08, 0x09, -}; -#else -static hda_nid_t alc880_adc_nids[2] = { - /* ADC1-2 */ - 0x08, 0x09, -}; -#endif - -#define ALC880_DIGOUT_NID 0x06 -#define ALC880_DIGIN_NID 0x0a - -static hda_nid_t alc260_dac_nids[1] = { - /* front */ - 0x02, -}; - -static hda_nid_t alc260_adc_nids[1] = { - /* ADC0 */ - 0x04, -}; -static hda_nid_t alc260_hp_adc_nids[1] = { - /* ADC1 */ - 0x05, -}; - -#define ALC260_DIGOUT_NID 0x03 -#define ALC260_DIGIN_NID 0x06 - -static struct hda_input_mux alc880_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, + /* dynamic controls, init_verbs and input_mux */ + struct auto_pin_cfg autocfg; + unsigned int num_kctl_alloc, num_kctl_used; + snd_kcontrol_new_t *kctl_alloc; + struct hda_input_mux private_imux; }; -//pshou 05/24/05 -static struct hda_input_mux alc880_6stack_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static struct hda_input_mux alc260_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; /* * input MUX handling @@ -221,6 +151,7 @@ static int alc_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); } + /* * channel mode setting */ @@ -229,133 +160,6 @@ struct alc_channel_mode { const struct hda_verb *sequence; }; - -/* - * channel source setting (2/6 channel selection for 3-stack) - */ - -/* - * set the path ways for 2 channel output - * need to set the codec line out and mic 1 pin widgets to inputs - */ -static struct hda_verb alc880_threestack_ch2_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* set pin widget 18h (mic1) for input, for mic also enable the vref */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* mute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - /* mute for Mic1 PW */ - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - { } /* end */ -}; - -/* - * 6ch mode - * need to set the codec line out and mic 1 pin widgets to outputs - */ -static struct hda_verb alc880_threestack_ch6_init[] = { - /* set pin widget 1Ah (line in) for output */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* set pin widget 18h (mic1) for output */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* unmute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, - /* unmute for Mic1 PW */ - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, - /* for rear channel output using Line In 1 - * set select widget connection (nid = 0x12) - to summer node - * for rear NID = 0x0f...offset 3 in connection list - */ - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x3 }, - /* for Mic1 - retask for center/lfe */ - /* set select widget connection (nid = 0x10) - to summer node for - * front CLFE NID = 0x0e...offset 2 in connection list - */ - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x2 }, - { } /* end */ -}; - -static struct alc_channel_mode alc880_threestack_modes[2] = { - { 2, alc880_threestack_ch2_init }, - { 6, alc880_threestack_ch6_init }, -}; - - -/* - * channel source setting (6/8 channel selection for 5-stack) - */ - -/* set the path ways for 6 channel output - * need to set the codec line out and mic 1 pin widgets to inputs - */ -static struct hda_verb alc880_fivestack_ch6_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* mute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - { } /* end */ -}; - -/* need to set the codec line out and mic 1 pin widgets to outputs */ -static struct hda_verb alc880_fivestack_ch8_init[] = { - /* set pin widget 1Ah (line in) for output */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* unmute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, - /* output for surround channel output using Line In 1 */ - /* set select widget connection (nid = 0x12) - to summer node - * for surr_rear NID = 0x0d...offset 1 in connection list - */ - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x1 }, - { } /* end */ -}; - -static struct alc_channel_mode alc880_fivestack_modes[2] = { - { 6, alc880_fivestack_ch6_init }, - { 8, alc880_fivestack_ch8_init }, -}; - -/* - * channel source setting for W810 system - * - * W810 has rear IO for: - * Front (DAC 02) - * Surround (DAC 03) - * Center/LFE (DAC 04) - * Digital out (06) - * - * The system also has a pair of internal speakers, and a headphone jack. - * These are both connected to Line2 on the codec, hence to DAC 02. - * - * There is a variable resistor to control the speaker or headphone - * volume. This is a hardware-only device without a software API. - * - * Plugging headphones in will disable the internal speakers. This is - * implemented in hardware, not via the driver using jack sense. In - * a similar fashion, plugging into the rear socket marked "front" will - * disable both the speakers and headphones. - * - * For input, there's a microphone jack, and an "audio in" jack. - * These may not do anything useful with this driver yet, because I - * haven't setup any initialization verbs for these yet... - */ - -static struct alc_channel_mode alc880_w810_modes[1] = { - { 6, NULL } -}; - -static struct alc_channel_mode alc880_z71v_modes[1] = { - { 2, NULL } -}; - -//pshou 05/19/05 -static struct alc_channel_mode alc880_sixstack_modes[1] = { - { 8, NULL }, -}; - -/* - */ static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -478,18 +282,79 @@ static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u #define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) + /* + * ALC880 3-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) + * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b + * HP = 0x19 */ -/* 3-stack mode - * Pin assignment: Front=0x14, Line-In/Rear=0x1a, Mic/CLFE=0x18, F-Mic=0x1b - * HP=0x19 +static hda_nid_t alc880_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x05, 0x04, 0x03 +}; + +static hda_nid_t alc880_adc_nids[3] = { + /* ADC0-2 */ + 0x07, 0x08, 0x09, +}; + +/* The datasheet says the node 0x07 is connected from inputs, + * but it shows zero connection in the real implementation on some devices. */ -static snd_kcontrol_new_t alc880_base_mixer[] = { +static hda_nid_t alc880_adc_nids_alt[2] = { + /* ADC1-2 */ + 0x08, 0x09, +}; + +#define ALC880_DIGOUT_NID 0x06 +#define ALC880_DIGIN_NID 0x0a + +static struct hda_input_mux alc880_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x3 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +/* channel source setting (2/6 channel selection for 3-stack) */ +/* 2ch mode */ +static struct hda_verb alc880_threestack_ch2_init[] = { + /* set line-in to input, mute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + /* set mic-in to input vref 80%, mute it */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* 6ch mode */ +static struct hda_verb alc880_threestack_ch6_init[] = { + /* set line-in to output, unmute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + /* set mic-in to output, unmute it */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ +}; + +static struct alc_channel_mode alc880_threestack_modes[2] = { + { 2, alc880_threestack_ch2_init }, + { 6, alc880_threestack_ch6_init }, +}; + +static snd_kcontrol_new_t alc880_three_stack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x1a, 2, HDA_INPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), @@ -504,13 +369,25 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - /* We don't use NID 0x07 - see above */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc880_ch_mode_info, + .get = alc880_ch_mode_get, + .put = alc880_ch_mode_put, + }, + { } /* end */ +}; + +/* capture mixer elements */ +static snd_kcontrol_new_t alc880_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* The multiple "Capture Source" controls confuse alsamixer @@ -519,49 +396,16 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { */ /* .name = "Capture Source", */ .name = "Input Source", - .count = 2, + .count = 3, .info = alc_mux_enum_info, .get = alc_mux_enum_get, .put = alc_mux_enum_put, }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc880_ch_mode_info, - .get = alc880_ch_mode_get, - .put = alc880_ch_mode_put, - }, { } /* end */ }; -/* 5-stack mode - * Pin assignment: Front=0x14, Rear=0x17, CLFE=0x16 - * Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19 - */ -static snd_kcontrol_new_t alc880_five_stack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), */ - HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), - /* We don't use NID 0x07 - see above */ +/* capture mixer elements (in case NID 0x07 not available) */ +static snd_kcontrol_new_t alc880_capture_alt_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), @@ -579,80 +423,77 @@ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { .get = alc_mux_enum_get, .put = alc_mux_enum_put, }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc880_ch_mode_info, - .get = alc880_ch_mode_get, - .put = alc880_ch_mode_put, - }, { } /* end */ }; -static snd_kcontrol_new_t alc880_w810_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, + + +/* + * ALC880 5-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), Side = 0x02 (0xd) + * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 + * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 + */ + +/* additional mixers to alc880_three_stack_mixer */ +static snd_kcontrol_new_t alc880_five_stack_mixer[] = { + HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), { } /* end */ }; -static snd_kcontrol_new_t alc880_z71v_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, +/* channel source setting (6/8 channel selection for 5-stack) */ +/* 6ch mode */ +static struct hda_verb alc880_fivestack_ch6_init[] = { + /* set line-in to input, mute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { } /* end */ }; -//pshou 05/24/05 +/* 8ch mode */ +static struct hda_verb alc880_fivestack_ch8_init[] = { + /* set line-in to output, unmute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ +}; + +static struct alc_channel_mode alc880_fivestack_modes[2] = { + { 6, alc880_fivestack_ch6_init }, + { 8, alc880_fivestack_ch8_init }, +}; + + +/* + * ALC880 6-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), Side = 0x05 (0x0f) + * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, + * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b + */ + +static hda_nid_t alc880_6st_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x03, 0x04, 0x05 +}; + +static struct hda_input_mux alc880_6stack_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +/* fixed 8-channels */ +static struct alc_channel_mode alc880_sixstack_modes[1] = { + { 8, NULL }, +}; + static snd_kcontrol_new_t alc880_six_stack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -674,25 +515,6 @@ static snd_kcontrol_new_t alc880_six_stack_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), */ - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -703,36 +525,44 @@ static snd_kcontrol_new_t alc880_six_stack_mixer[] = { { } /* end */ }; -// 03/08/05 Fujitsu -static snd_kcontrol_new_t alc880_2_jack_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ + +/* + * ALC880 W810 model + * + * W810 has rear IO for: + * Front (DAC 02) + * Surround (DAC 03) + * Center/LFE (DAC 04) + * Digital out (06) + * + * The system also has a pair of internal speakers, and a headphone jack. + * These are both connected to Line2 on the codec, hence to DAC 02. + * + * There is a variable resistor to control the speaker or headphone + * volume. This is a hardware-only device without a software API. + * + * Plugging headphones in will disable the internal speakers. This is + * implemented in hardware, not via the driver using jack sense. In + * a similar fashion, plugging into the rear socket marked "front" will + * disable both the speakers and headphones. + * + * For input, there's a microphone jack, and an "audio in" jack. + * These may not do anything useful with this driver yet, because I + * haven't setup any initialization verbs for these yet... + */ + +static hda_nid_t alc880_w810_dac_nids[3] = { + /* front, rear/surround, clfe */ + 0x02, 0x03, 0x04 }; -//pshou 04/24/05 -static snd_kcontrol_new_t alc880_asus_mixer[] = { +/* fixed 6 channels */ +static struct alc_channel_mode alc880_w810_modes[1] = { + { 6, NULL } +}; + +/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ +static snd_kcontrol_new_t alc880_w810_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -741,41 +571,80 @@ static snd_kcontrol_new_t alc880_asus_mixer[] = { HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + { } /* end */ +}; + + +/* + * Z710V model + * + * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) + * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), Line = 0x1a + */ + +static hda_nid_t alc880_z71v_dac_nids[1] = { + 0x02 +}; +#define ALC880_Z71V_HP_DAC 0x03 + +/* fixed 2 channels */ +static struct alc_channel_mode alc880_2_jack_modes[1] = { + { 2, NULL } +}; + +static snd_kcontrol_new_t alc880_z71v_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc880_ch_mode_info, - .get = alc880_ch_mode_get, - .put = alc880_ch_mode_put, - }, { } /* end */ }; -// pshou 05/03/05 -static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { + +/* FIXME! */ +/* + * ALC880 F1734 model + * + * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) + * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 + */ + +static hda_nid_t alc880_f1734_dac_nids[1] = { + 0x03 +}; +#define ALC880_F1734_HP_DAC 0x02 + +static snd_kcontrol_new_t alc880_f1734_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + + +/* FIXME! */ +/* + * ALC880 ASUS model + * + * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) + * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, + * Mic = 0x18, Line = 0x1a + */ + +#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ +#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ + +static snd_kcontrol_new_t alc880_asus_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -788,27 +657,8 @@ static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -818,7 +668,26 @@ static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { }, { } /* end */ }; + +/* FIXME! */ +/* + * ALC880 ASUS W1V model + * + * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) + * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, + * Mic = 0x18, Line = 0x1a, Line2 = 0x1b + */ + +/* additional mixers to alc880_asus_mixer */ +static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { + HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), + { } /* end */ +}; + + /* + * build control elements */ static int alc_build_controls(struct hda_codec *codec) { @@ -845,453 +714,297 @@ static int alc_build_controls(struct hda_codec *codec) return 0; } + /* * initialize the codec volumes, etc */ -#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) -#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) -#define AMP_OUT_MUTE 0xb080 -#define AMP_OUT_UNMUTE 0xb000 -#define AMP_OUT_ZERO 0xb000 -#define PIN_IN 0x20 -#define PIN_VREF80 0x24 -#define PIN_VREF50 0x21 -#define PIN_OUT 0x40 -#define PIN_HP 0xc0 - -static struct hda_verb alc880_init_verbs_three_stack[] = { - /* Set pin widgets for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* unmute capture amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ +/* + * generic initialization of ADC, input mixers and output mixers + */ +static struct hda_verb alc880_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute capture1 amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute capture2 amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* set vol=0 front mixer amp */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute front-out pin widget amp (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 rear mixer amp */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* mute line-in pin widget amp left and right (no gain on this amp) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* set vol=0 clfe mixer amp */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* mute mic pin widget amp left and right (no gain on this amp) */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* using rear surround as the path for headphone output */ - /* set vol=0 rear surround mixer amp */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* PASD 3 stack boards use the Mic 2 as the headphone output */ - /* need to program the selector associated with the Mic 2 pin widget to - * surround path (index 0x01) for headphone output */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* need to retask the Mic 2 pin widget to output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer widget(nid=0x0B) - * to support the input path of analog loopback + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for front panel * mic (mic 2) */ - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ - /* mute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* mute Mic 1 */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* mute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* Unmute input amps for the line out paths to support the output path of - * analog loopback - * the mixers on the output path has 2 inputs, one from the DAC and one - * from the mixer + /* + * Set up output mixers (0x0c - 0x0f) */ - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute Surround (used as HP) out path */ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute C/LFE out path */ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute rear Surround out path */ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, { } }; -static struct hda_verb alc880_init_verbs_five_stack[] = { - /* Set pin widgets for output */ +/* + * 3-stack pin configuration: + * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b + */ +static struct hda_verb alc880_pin_3stack_init_verbs[] = { + /* + * preset connection lists of input pins + * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround + */ + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ + + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line In pin widget for input */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line2 (as front mic) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* CD pin widget for input */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* mute capture amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* mute amp1 left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* set vol=0 front mixer amp */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute front-out pin widget amp (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 rear mixer amp */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute rear-out pin widget (no gain on this amp) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 clfe mixer amp */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute clfe-pin widget amp (no gain on this amp) */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* using rear surround as the path for headphone output */ - /* set vol=0 rear surround mixer amp */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* PASD 3 stack boards use the Mic 2 as the headphone output */ - /* need to program the selector associated with the Mic 2 pin widget to - * surround path (index 0x01) for headphone output - */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* need to retask the Mic 2 pin widget to output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + { } +}; - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer - * widget(nid=0x0B) to support the input path of analog loopback +/* + * 5-stack pin configuration: + * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, + * line-in/side = 0x1a, f-mic = 0x1b + */ +static struct hda_verb alc880_pin_5stack_init_verbs[] = { + /* + * preset connection lists of input pins + * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround */ - /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ - /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ - /* Unmute input amps for the line out paths to support the output path of - * analog loopback - * the mixers on the output path has 2 inputs, one from the DAC and - * one from the mixer + /* + * Set pin mode and muting */ - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute Surround (used as HP) out path */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute C/LFE out path */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute rear Surround out path */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* set pin widgets 0x14-0x17 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* unmute pins for output (no gain on this amp) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line2 (as front mic) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, { } }; -static struct hda_verb alc880_w810_init_verbs[] = { - /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* front channel selector/amp: output 0: unmuted, max volume */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* front out pin: muted, (no volume selection) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, +/* + * W810 pin configuration: + * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b + */ +static struct hda_verb alc880_pin_w810_init_verbs[] = { + /* hphone/speaker input selector: front DAC */ + {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* front out pin: NOT headphone enable, out enable, vref disabled */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - - /* surround channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* surround channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* surround channel selector/amp: output 0: unmuted, max volume */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* surround out pin: muted, (no volume selection) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* surround out pin: NOT headphone enable, out enable, vref disabled */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - - /* c/lfe channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* c/lfe channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* c/lfe channel selector/amp: output 0: unmuted, max volume */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* c/lfe out pin: muted, (no volume selection) */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* c/lfe out pin: NOT headphone enable, out enable, vref disabled */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* hphone/speaker input selector: front DAC */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - - /* hphone/speaker out pin: muted, (no volume selection) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* hphone/speaker out pin: NOT headphone enable, out enable, vref disabled */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - { } }; -static struct hda_verb alc880_z71v_init_verbs[] = { - /* front channel selector/amp: muted, DAC and mix (no vol) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* front channel selector/amp: output 0: vol=0 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* front out pin: unmuted, (no volume selection) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* front out pin: NOT headphone enable, out enable, vref disabled */ +/* + * Z71V pin configuration: + * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) + */ +static struct hda_verb alc880_pin_z71v_init_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* headphone channel selector/amp: muted, DAC and mix (no vol) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* headphone channel selector/amp: output 0: vol=0 */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* headphone out pin: muted, (no volume selection) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* headpohne out pin: headphone enable, out enable, vref disabled */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer - * widget(nid=0x0B) to support the input path of analog loopback - */ - /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ - /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, { } }; -//pshou 05/24/05 -static struct hda_verb alc880_six_stack_init_verbs[] = { +/* + * 6-stack pin configuration: + * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19, + * line = 0x1a, HP = 0x1b + */ +static struct hda_verb alc880_pin_6stack_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + { } +}; + +/* FIXME! */ +/* + * F1734 pin configuration: + * HP = 0x14, speaker-out = 0x15, mic = 0x18 + */ +static struct hda_verb alc880_pin_f1734_init_verbs[] = { {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer - * widget(nid=0x0B) to support the input path of analog loopback - */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* unmute Mic 2 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Front out path */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute Surround (used as HP) out path */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute C/LFE out path */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mute */ - /* Unmute rear Surround out path */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - { } -}; -static struct hda_verb alc880_2_jack_init_verbs[] = { - /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x0C, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1B, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, { } }; -static struct hda_verb alc880_asus_init_verbs[] = { +/* FIXME! */ +/* + * ASUS pin configuration: + * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a + */ +static struct hda_verb alc880_pin_asus_init_verbs[] = { {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ - /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } +}; - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute Surround (used as HP) out path */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute C/LFE out path */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +/* Enable GPIO mask and set output */ +static struct hda_verb alc880_gpio1_init_verbs[] = { + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, +}; - { } +/* Enable GPIO mask and set output */ +static struct hda_verb alc880_gpio2_init_verbs[] = { + {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, }; +/* + */ + static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - snd_hda_sequence_write(codec, spec->init_verbs); + unsigned int i; + + for (i = 0; i < spec->num_init_verbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); return 0; } @@ -1305,9 +1018,8 @@ static int alc_resume(struct hda_codec *codec) int i; alc_init(codec); - for (i = 0; i < spec->num_mixers; i++) { + for (i = 0; i < spec->num_mixers; i++) snd_hda_resume_ctls(codec, spec->mixers[i]); - } if (spec->multiout.dig_out_nid) snd_hda_resume_spdif_out(codec); if (spec->dig_in_nid) @@ -1399,7 +1111,7 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, - .nid = 0x02, /* NID to query formats and rates */ + /* NID is set in alc_build_pcms */ .ops = { .open = alc880_playback_pcm_open, .prepare = alc880_playback_pcm_prepare, @@ -1411,9 +1123,7 @@ static struct hda_pcm_stream alc880_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, - .nid = 0x08, /* NID to query formats and rates - * (0x07 might be broken on some devices) - */ + /* NID is set in alc_build_pcms */ .ops = { .prepare = alc880_capture_pcm_prepare, .cleanup = alc880_capture_pcm_cleanup @@ -1449,7 +1159,9 @@ static int alc_build_pcms(struct hda_codec *codec) info->name = spec->stream_name_analog; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; for (i = 0; i < spec->num_channel_mode; i++) { @@ -1477,7 +1189,18 @@ static int alc_build_pcms(struct hda_codec *codec) static void alc_free(struct hda_codec *codec) { - kfree(codec->spec); + struct alc_spec *spec = codec->spec; + unsigned int i; + + if (! spec) + return; + + if (spec->kctl_alloc) { + for (i = 0; i < spec->num_kctl_used; i++) + kfree(spec->kctl_alloc[i].name); + kfree(spec->kctl_alloc); + } + kfree(spec); } /* @@ -1840,7 +1563,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, - { .modelname = "asua", .config = ALC880_ASUS }, + { .modelname = "asus", .config = ALC880_ASUS }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, @@ -1869,10 +1592,8 @@ static struct hda_board_config alc880_cfg_tbl[] = { * configuration template - to be copied to the spec instance */ struct alc_config_preset { - snd_kcontrol_new_t *mixers; - unsigned int front_panel: 1; /* optional */ - unsigned int gpio_payload; /* optional */ - struct hda_verb *init_verbs; + snd_kcontrol_new_t *mixers[4]; + const struct hda_verb *init_verbs[4]; unsigned int num_dacs; hda_nid_t *dac_nids; hda_nid_t dig_out_nid; /* optional */ @@ -1886,174 +1607,134 @@ struct alc_config_preset { static struct alc_config_preset alc880_presets[] = { [ALC880_3ST] = { - .mixers = alc880_base_mixer, - .init_verbs = alc880_init_verbs_three_stack, + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .front_panel = 1, .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), .channel_mode = alc880_threestack_modes, .input_mux = &alc880_capture_source, }, [ALC880_3ST_DIG] = { - .mixers = alc880_base_mixer, - .init_verbs = alc880_init_verbs_three_stack, + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .front_panel = 1, .dac_nids = alc880_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), .channel_mode = alc880_threestack_modes, .input_mux = &alc880_capture_source, }, [ALC880_5ST] = { - .mixers = alc880_five_stack_mixer, - .init_verbs = alc880_init_verbs_five_stack, - .front_panel = 1, + .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer}, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), .channel_mode = alc880_fivestack_modes, .input_mux = &alc880_capture_source, }, [ALC880_5ST_DIG] = { - .mixers = alc880_five_stack_mixer, - .init_verbs = alc880_init_verbs_five_stack, - .front_panel = 1, + .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), .dac_nids = alc880_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), .channel_mode = alc880_fivestack_modes, .input_mux = &alc880_capture_source, }, [ALC880_6ST_DIG] = { - .mixers = alc880_six_stack_mixer, - .init_verbs = alc880_six_stack_init_verbs, - .front_panel = 1, + .mixers = { alc880_six_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), .dac_nids = alc880_6st_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), .channel_mode = alc880_sixstack_modes, .input_mux = &alc880_6stack_capture_source, }, [ALC880_W810] = { - .mixers = alc880_w810_base_mixer, - .init_verbs = alc880_w810_init_verbs, - .gpio_payload = 0x2, + .mixers = { alc880_w810_base_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), .dac_nids = alc880_w810_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - // No dedicated headphone socket - it's shared with built-in speakers. - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), .channel_mode = alc880_w810_modes, .input_mux = &alc880_capture_source, }, [ALC880_Z71V] = { - .mixers = alc880_z71v_mixer, - .init_verbs = alc880_z71v_init_verbs, + .mixers = { alc880_z71v_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs, + alc880_gpio2_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), .dac_nids = alc880_z71v_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_z71v_modes), - .channel_mode = alc880_z71v_modes, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, }, [ALC880_F1734] = { - .mixers = alc880_2_jack_mixer, - .init_verbs = alc880_2_jack_init_verbs, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_z71v_modes), - .channel_mode = alc880_z71v_modes, + .mixers = { alc880_f1734_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_f1734_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), + .dac_nids = alc880_f1734_dac_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, }, [ALC880_ASUS] = { - .mixers = alc880_asus_mixer, - .init_verbs = alc880_asus_init_verbs, - .gpio_payload = 0x1, - .front_panel = 1, - .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), - .dac_nids = alc880_w810_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, .input_mux = &alc880_capture_source, }, [ALC880_ASUS_DIG] = { - .mixers = alc880_asus_mixer, - .init_verbs = alc880_asus_init_verbs, - .gpio_payload = 0x1, - .front_panel = 1, - .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), - .dac_nids = alc880_w810_dac_nids, + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, .input_mux = &alc880_capture_source, }, [ALC880_ASUS_W1V] = { - .mixers = alc880_asus_w1v_mixer, - .init_verbs = alc880_asus_init_verbs, - .gpio_payload = 0x1, - .front_panel = 1, - .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), - .dac_nids = alc880_w810_dac_nids, + .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, .input_mux = &alc880_capture_source, }, [ALC880_UNIWILL_DIG] = { - .mixers = alc880_asus_mixer, - .init_verbs = alc880_asus_init_verbs, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, .input_mux = &alc880_capture_source, }, #ifdef CONFIG_SND_DEBUG [ALC880_TEST] = { - .mixers = alc880_test_mixer, - .init_verbs = alc880_test_init_verbs, + .mixers = { alc880_test_mixer }, + .init_verbs = { alc880_test_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), .dac_nids = alc880_test_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_test_modes), .channel_mode = alc880_test_modes, .input_mux = &alc880_test_capture_source, @@ -2061,11 +1742,333 @@ static struct alc_config_preset alc880_presets[] = { #endif }; +/* + * Automatic parse of I/O pins from the BIOS configuration + */ + +#define NUM_CONTROL_ALLOC 32 +#define NUM_VERB_ALLOC 32 + +enum { + ALC_CTL_WIDGET_VOL, + ALC_CTL_WIDGET_MUTE, + ALC_CTL_BIND_MUTE, +}; +static snd_kcontrol_new_t alc880_control_templates[] = { + HDA_CODEC_VOLUME(NULL, 0, 0, 0), + HDA_CODEC_MUTE(NULL, 0, 0, 0), + ALC_BIND_MUTE(NULL, 0, 0, 0), +}; + +/* add dynamic controls */ +static int add_control(struct alc_spec *spec, int type, const char *name, unsigned long val) +{ + snd_kcontrol_new_t *knew; + + if (spec->num_kctl_used >= spec->num_kctl_alloc) { + int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; + + knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ + if (! knew) + return -ENOMEM; + if (spec->kctl_alloc) { + memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); + kfree(spec->kctl_alloc); + } + spec->kctl_alloc = knew; + spec->num_kctl_alloc = num; + } + + knew = &spec->kctl_alloc[spec->num_kctl_used]; + *knew = alc880_control_templates[type]; + knew->name = snd_kmalloc_strdup(name, GFP_KERNEL); + if (! knew->name) + return -ENOMEM; + knew->private_value = val; + spec->num_kctl_used++; + return 0; +} + +#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) +#define alc880_fixed_pin_idx(nid) ((nid) - 0x14) +#define alc880_is_multi_pin(nid) ((nid) >= 0x18) +#define alc880_multi_pin_idx(nid) ((nid) - 0x18) +#define alc880_is_input_pin(nid) ((nid) >= 0x18) +#define alc880_input_pin_idx(nid) ((nid) - 0x18) +#define alc880_idx_to_dac(nid) ((nid) + 0x02) +#define alc880_dac_to_idx(nid) ((nid) - 0x02) +#define alc880_idx_to_mixer(nid) ((nid) + 0x0c) +#define alc880_idx_to_selector(nid) ((nid) + 0x10) +#define ALC880_PIN_CD_NID 0x1c + +/* fill in the dac_nids table from the parsed pin configuration */ +static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int assigned[4]; + int i, j; + + memset(assigned, 0, sizeof(assigned)); + + /* check the pins hardwired to audio widget */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (alc880_is_fixed_pin(nid)) { + int idx = alc880_fixed_pin_idx(nid); + spec->multiout.dac_nids[i] = alc880_dac_to_idx(idx); + assigned[idx] = 1; + } + } + /* left pins can be connect to any audio widget */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (alc880_is_fixed_pin(nid)) + continue; + /* search for an empty channel */ + for (j = 0; j < cfg->line_outs; j++) { + if (! assigned[j]) { + spec->multiout.dac_nids[i] = alc880_idx_to_dac(j); + assigned[j] = 1; + break; + } + } + } + spec->multiout.num_dacs = cfg->line_outs; + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; + hda_nid_t nid; + int i, err; + + for (i = 0; i < cfg->line_outs; i++) { + if (! spec->multiout.dac_nids[i]) + continue; + nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); + if (i == 2) { + /* Center/LFE */ + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT))) < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) + return err; + } + } + + return 0; +} + +/* add playback controls for HP output */ +static int alc880_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) +{ + hda_nid_t nid; + int err; + + if (! pin) + return 0; + + if (alc880_is_fixed_pin(pin)) { + nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); + if (! spec->multiout.dac_nids[0]) { + /* use this as the primary output */ + spec->multiout.dac_nids[0] = nid; + if (! spec->multiout.num_dacs) + spec->multiout.num_dacs = 1; + } else + /* specify the DAC as the extra HP output */ + spec->multiout.hp_nid = nid; + /* control HP volume/switch on the output mixer amp */ + nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) + return err; + } else if (alc880_is_multi_pin(pin)) { + /* set manual connection */ + if (! spec->multiout.dac_nids[0]) { + /* use this as the primary output */ + spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin)); + if (! spec->multiout.num_dacs) + spec->multiout.num_dacs = 1; + } + /* we have only a switch on HP-out PIN */ + if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT))) < 0) + return err; + } + return 0; +} + +/* create input playback/capture controls for the given pin */ +static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname) +{ + char name[32]; + int err, idx; + + sprintf(name, "%s Playback Volume", ctlname); + idx = alc880_input_pin_idx(pin); + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) + return err; + sprintf(name, "%s Playback Switch", ctlname); + if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) + return err; + return 0; +} + +/* create playback/capture controls for input pins */ +static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) +{ + static char *labels[AUTO_PIN_LAST] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" + }; + struct hda_input_mux *imux = &spec->private_imux; + int i, err; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (alc880_is_input_pin(cfg->input_pins[i])) { + err = new_analog_input(spec, cfg->input_pins[i], labels[i]); + if (err < 0) + return err; + imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].index = alc880_input_pin_idx(cfg->input_pins[i]); + imux->num_items++; + } + } + return 0; +} + +static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, + int dac_idx) +{ + /* set as output */ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + /* need the manual connection? */ + if (alc880_is_multi_pin(nid)) { + struct alc_spec *spec = codec->spec; + int idx = alc880_multi_pin_idx(nid); + snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, + AC_VERB_SET_CONNECT_SEL, + alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); + } +} + +static void alc880_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); + } +} + +static void alc880_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + + pin = spec->autocfg.hp_pin; + if (pin) /* connect to front */ + alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); +} + +static void alc880_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t nid = spec->autocfg.input_pins[i]; + if (alc880_is_input_pin(nid)) { + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); + if (nid != ALC880_PIN_CD_NID) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } + } +} + +/* parse the BIOS configuration and set up the alc_spec */ +/* return 1 if successful, 0 if the proper config is not found, or a negative error code */ +static int alc880_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + + if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0) + return err; + if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0) + return err; + if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin) + return 0; /* can't find valid BIOS pin config */ + if ((err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || + (err = alc880_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || + (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + if (spec->autocfg.dig_out_pin) + spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = ALC880_DIGIN_NID; + + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + + spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; + + spec->input_mux = &spec->private_imux; + + return 1; +} + +/* init callback for auto-configuration model -- overriding the default init */ +static int alc880_auto_init(struct hda_codec *codec) +{ + alc_init(codec); + alc880_auto_init_multi_out(codec); + alc880_auto_init_hp_out(codec); + alc880_auto_init_analog_input(codec); + return 0; +} + +/* + * OK, here we have finally the patch for ALC880 + */ + static int patch_alc880(struct hda_codec *codec) { struct alc_spec *spec; int board_config; - const struct alc_config_preset *preset; + int i, err; spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -2076,30 +2079,52 @@ static int patch_alc880(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { - snd_printd(KERN_INFO "hda_codec: Unknown model for ALC880\n"); - board_config = ALC880_3ST; + printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n"); + board_config = ALC880_AUTO; } - preset = &alc880_presets[board_config]; - - spec->mixers[spec->num_mixers] = preset->mixers; - snd_assert(spec->mixers[0], kfree(spec);return -EINVAL); - spec->num_mixers++; - /* some MBs need GPIO setup */ - if (preset->gpio_payload) { - /* Enable mask and set output */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, preset->gpio_payload); - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, preset->gpio_payload); - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, preset->gpio_payload); + if (board_config == ALC880_AUTO) { + /* automatic parse from the BIOS config */ + err = alc880_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (! err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 3-stack mode...\n"); + board_config = ALC880_3ST; + } } - spec->front_panel = preset->front_panel; - spec->init_verbs = preset->init_verbs; - spec->channel_mode = preset->channel_mode; - spec->num_channel_mode = preset->num_channel_mode; + if (board_config != ALC880_AUTO) { + /* set up from the preset table */ + const struct alc_config_preset *preset; + + preset = &alc880_presets[board_config]; + + for (i = 0; preset->mixers[i]; i++) { + snd_assert(spec->num_mixers < ARRAY_SIZE(spec->mixers), break); + spec->mixers[spec->num_mixers++] = preset->mixers[i]; + } + for (i = 0; preset->init_verbs[i]; i++) { + snd_assert(spec->num_init_verbs < ARRAY_SIZE(spec->init_verbs), break); + spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i]; + } + + spec->channel_mode = preset->channel_mode; + spec->num_channel_mode = preset->num_channel_mode; + + spec->multiout.max_channels = spec->channel_mode[0].channels; + + spec->multiout.num_dacs = preset->num_dacs; + spec->multiout.dac_nids = preset->dac_nids; + spec->multiout.dig_out_nid = preset->dig_out_nid; + spec->multiout.hp_nid = preset->hp_nid; + + spec->input_mux = preset->input_mux; + + spec->num_adc_nids = preset->num_adc_nids; + spec->adc_nids = preset->adc_nids; + } spec->stream_name_analog = "ALC880 Analog"; spec->stream_analog_playback = &alc880_pcm_analog_playback; @@ -2109,26 +2134,64 @@ static int patch_alc880(struct hda_codec *codec) spec->stream_digital_playback = &alc880_pcm_digital_playback; spec->stream_digital_capture = &alc880_pcm_digital_capture; - spec->multiout.max_channels = spec->channel_mode[0].channels; - - spec->multiout.num_dacs = preset->num_dacs; - spec->multiout.dac_nids = preset->adc_nids; - spec->multiout.dig_out_nid = preset->dig_out_nid; - spec->multiout.hp_nid = preset->hp_nid; - - spec->input_mux = preset->input_mux; - spec->num_adc_nids = preset->num_adc_nids; - spec->adc_nids = preset->adc_nids; + if (! spec->adc_nids && spec->input_mux) { + /* check whether NID 0x07 is valid */ + unsigned int wcap = snd_hda_param_read(codec, alc880_adc_nids[0], + AC_PAR_AUDIO_WIDGET_CAP); + wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ + if (wcap != AC_WID_AUD_IN) { + spec->adc_nids = alc880_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); + spec->mixers[spec->num_mixers] = alc880_capture_alt_mixer; + spec->num_mixers++; + } else { + spec->adc_nids = alc880_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); + spec->mixers[spec->num_mixers] = alc880_capture_mixer; + spec->num_mixers++; + } + } codec->patch_ops = alc_patch_ops; + if (board_config == ALC880_AUTO) + codec->patch_ops.init = alc880_auto_init; return 0; } + /* * ALC260 support */ +static hda_nid_t alc260_dac_nids[1] = { + /* front */ + 0x02, +}; + +static hda_nid_t alc260_adc_nids[1] = { + /* ADC0 */ + 0x04, +}; + +static hda_nid_t alc260_hp_adc_nids[1] = { + /* ADC1 */ + 0x05, +}; + +#define ALC260_DIGOUT_NID 0x03 +#define ALC260_DIGIN_NID 0x06 + +static struct hda_input_mux alc260_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + /* * This is just place-holder, so there's something for alc_build_pcms to look * at when it calculates the maximum number of channels. ALC260 has no mixer @@ -2139,7 +2202,7 @@ static struct alc_channel_mode alc260_modes[1] = { { 2, NULL }, }; -snd_kcontrol_new_t alc260_base_mixer[] = { +static snd_kcontrol_new_t alc260_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), @@ -2168,7 +2231,7 @@ snd_kcontrol_new_t alc260_base_mixer[] = { { } /* end */ }; -snd_kcontrol_new_t alc260_hp_mixer[] = { +static snd_kcontrol_new_t alc260_hp_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), @@ -2260,14 +2323,12 @@ static struct hda_pcm_stream alc260_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, - .nid = 0x2, }; static struct hda_pcm_stream alc260_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, - .nid = 0x4, }; static struct hda_board_config alc260_cfg_tbl[] = { @@ -2296,7 +2357,7 @@ static int patch_alc260(struct hda_codec *codec) switch (board_config) { case ALC260_HP: - spec->mixers[spec->num_mixers] = alc260_base_mixer; + spec->mixers[spec->num_mixers] = alc260_hp_mixer; spec->num_mixers++; break; default: @@ -2305,7 +2366,9 @@ static int patch_alc260(struct hda_codec *codec) break; } - spec->init_verbs = alc260_init_verbs; + spec->init_verbs[0] = alc260_init_verbs; + spec->num_init_verbs = 1; + spec->channel_mode = alc260_modes; spec->num_channel_mode = ARRAY_SIZE(alc260_modes); @@ -2320,7 +2383,6 @@ static int patch_alc260(struct hda_codec *codec) spec->input_mux = &alc260_capture_source; switch (board_config) { case ALC260_HP: - spec->stream_analog_capture->nid = 5; spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); spec->adc_nids = alc260_hp_adc_nids; break; @@ -2335,6 +2397,7 @@ static int patch_alc260(struct hda_codec *codec) return 0; } + /* * ALC882 support * @@ -2463,42 +2526,35 @@ static struct hda_verb alc882_init_verbs[] = { {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin: to output mode */ + /* Front Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Front Pin: mute amp left and right (no volume) */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* select Front mixer (0x0c, index 0) */ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Rear Pin */ + /* Rear Pin: output 1 (0x0d) */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Rear Pin: mute amp left and right (no volume) */ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* select Rear mixer (0x0d, index 1) */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* CLFE Pin */ + /* CLFE Pin: output 2 (0x0e) */ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* CLFE Pin: mute amp left and right (no volume) */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* select CLFE mixer (0x0e, index 2) */ {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin */ + /* Side Pin: output 3 (0x0f) */ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Side Pin: mute amp left and right (no volume) */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* select Side mixer (0x0f, index 3) */ {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Headphone Pin */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Headphone Pin: mute amp left and right (no volume) */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* select Front mixer (0x0c, index 0) */ - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Mic (rear) pin widget for input and vref at 80% */ + /* Mic (rear) pin: input vref at 80% */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Front Mic pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Line In pin widget for input */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* CD pin widget for input */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -2548,8 +2604,9 @@ static int patch_alc882(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; spec->dig_in_nid = ALC880_DIGIN_NID; - spec->front_panel = 1; - spec->init_verbs = alc882_init_verbs; + spec->init_verbs[0] = alc882_init_verbs; + spec->num_init_verbs = 1; + spec->channel_mode = alc882_ch_modes; spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes); -- cgit v0.10.2 From ee3b4c60f452f8e24fe30ae73cb97da1beda0ca2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 14 Jun 2005 10:18:20 +0200 Subject: [ALSA] via82xx - Fix info text about dxs_support option VIA82xx driver Fixed the info text about dxs_support option (suggest dxs_support=5). Signed-off-by: Takashi Iwai diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index e861a01..7e570a4 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2211,8 +2211,9 @@ static int __devinit check_dxs_list(struct pci_dev *pci) * not detected, try 48k rate only to be sure. */ printk(KERN_INFO "via82xx: Assuming DXS channels with 48k fixed sample rate.\n"); - printk(KERN_INFO " Please try dxs_support=1 or dxs_support=4 option\n"); + printk(KERN_INFO " Please try dxs_support=5 option\n"); printk(KERN_INFO " and report if it works on your machine.\n"); + printk(KERN_INFO " For more details, read ALSA-Configuration.txt.\n"); return VIA_DXS_48K; }; -- cgit v0.10.2 From dabbed6f729d806092851150ca3dd9efe2b64b58 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 14 Jun 2005 10:19:34 +0200 Subject: [ALSA] SigmaTel HDA SPDIF and input mux updates HDA Codec driver Adds SPDIF in/out support to the SigmaTel HDA codecs. Now builds the input mux control element names from the defcfg regs. Signed-off-by: Matt Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1534e20..013be2e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -42,9 +42,11 @@ struct sigmatel_spec { /* capture */ hda_nid_t *adc_nids; - hda_nid_t *mux_nids; unsigned int num_adcs; + hda_nid_t *mux_nids; + unsigned int num_muxes; hda_nid_t capture_nid; + hda_nid_t dig_in_nid; /* power management*/ hda_nid_t *pstate_nids; @@ -62,7 +64,8 @@ struct sigmatel_spec { snd_kcontrol_new_t *mixer; /* capture source */ - const struct hda_input_mux *input_mux; + struct hda_input_mux input_mux; + char input_labels[HDA_MAX_NUM_INPUTS][16]; unsigned int cur_mux[2]; /* channel mode */ @@ -105,8 +108,8 @@ static hda_nid_t stac922x_dac_nids[4] = { 0x02, 0x03, 0x04, 0x05, }; -static hda_nid_t stac922x_pstate_nids[7] = { - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +static hda_nid_t stac922x_pstate_nids[8] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11, }; static hda_nid_t stac922x_pin_nids[10] = { @@ -118,7 +121,7 @@ static int stac92xx_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); + return snd_hda_input_mux_info(&spec->input_mux, uinfo); } static int stac92xx_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) @@ -137,7 +140,7 @@ static int stac92xx_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t struct sigmatel_spec *spec = codec->spec; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); } @@ -192,30 +195,6 @@ static snd_kcontrol_new_t stac922x_mixer[] = { { } /* end */ }; -static struct hda_input_mux stac9200_input_mux = { - .num_items = 5, - .items = { - { "Port B", 0x0 }, - { "Port C", 0x1 }, - { "Port D", 0x2 }, - { "Port A", 0x3 }, - { "CD", 0x4 }, - } -}; - -static struct hda_input_mux stac922x_input_mux = { - .num_items = 7, - .items = { - { "Port E", 0x0 }, - { "CD", 0x1 }, - { "Port F", 0x2 }, - { "Port B", 0x3 }, - { "Port C", 0x4 }, - { "Port D", 0x5 }, - { "Port A", 0x6 }, - } -}; - static int stac92xx_build_controls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -224,19 +203,28 @@ static int stac92xx_build_controls(struct hda_codec *codec) err = snd_hda_add_new_ctls(codec, spec->mixer); if (err < 0) return err; - - return 0; + if (spec->multiout.dig_out_nid) { + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + if (err < 0) + return err; + } + if (spec->dig_in_nid) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); + if (err < 0) + return err; + } + return 0; } #ifdef STAC_TEST static unsigned int stac9200_pin_configs[8] = { - 0x40000100, 0x40000100, 0x0221401f, 0x01114010, + 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; static unsigned int stac922x_pin_configs[14] = { 0x40000100, 0x40000100, 0x40000100, 0x01114010, - 0x01813122, 0x40000100, 0x40000100, 0x40000100, + 0x01813122, 0x40000100, 0x01447010, 0x01c47010, 0x40000100, 0x40000100, }; @@ -299,29 +287,89 @@ static int stac92xx_set_vref(struct hda_codec *codec, hda_nid_t nid) return 0; } +/* + * retrieve the default device type from the default config value + */ +#define get_defcfg_type(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) +#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) + static int stac92xx_config_pin(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_cfg) { - switch((pin_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) { + struct sigmatel_spec *spec = codec->spec; + u32 location = get_defcfg_location(pin_cfg); + char *label; + const char *type = NULL; + int ainput = 0; + + switch(get_defcfg_type(pin_cfg)) { case AC_JACK_HP_OUT: /* Enable HP amp */ stac92xx_set_pinctl(codec, nid, AC_PINCTL_HP_EN); /* Fall through */ + case AC_JACK_SPDIF_OUT: case AC_JACK_LINE_OUT: case AC_JACK_SPEAKER: /* Enable output */ stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); break; + case AC_JACK_SPDIF_IN: + stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); + break; case AC_JACK_MIC_IN: + if ((location & 0x0f) == AC_JACK_LOC_FRONT) + type = "Front Mic"; + else + type = "Mic"; + ainput = 1; /* Set vref */ stac92xx_set_vref(codec, nid); + stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); + break; case AC_JACK_CD: + type = "CD"; + ainput = 1; + stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); + break; case AC_JACK_LINE_IN: + if ((location & 0x0f) == AC_JACK_LOC_FRONT) + type = "Front Line"; + else + type = "Line"; + ainput = 1; + stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); + break; case AC_JACK_AUX: - /* Enable input */ + if ((location & 0x0f) == AC_JACK_LOC_FRONT) + type = "Front Aux"; + else + type = "Aux"; + ainput = 1; stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); break; } + if (ainput) { + hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; + int i, j, num_cons, index = -1; + if (!type) + type = "Input"; + label = spec->input_labels[spec->input_mux.num_items]; + strcpy(label, type); + spec->input_mux.items[spec->input_mux.num_items].label = label; + for (i=0; inum_muxes; i++) { + num_cons = snd_hda_get_connections(codec, spec->mux_nids[i], con_lst, HDA_MAX_NUM_INPUTS); + for (j=0; j= 0) + break; + } + spec->input_mux.items[spec->input_mux.num_items].index = index; + spec->input_mux.num_items++; + } + return 0; } @@ -402,6 +450,26 @@ static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, } /* + * Digital playback callbacks + */ +static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + + +/* * Analog capture callbacks */ static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -427,6 +495,24 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } +static struct hda_pcm_stream stac92xx_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in stac92xx_build_pcms */ + .ops = { + .open = stac92xx_dig_playback_pcm_open, + .close = stac92xx_dig_playback_pcm_close + }, +}; + +static struct hda_pcm_stream stac92xx_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in stac92xx_build_pcms */ +}; + static struct hda_pcm_stream stac92xx_pcm_analog_playback = { .substreams = 1, .channels_min = 2, @@ -464,6 +550,20 @@ static int stac92xx_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->capture_nid; + if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + codec->num_pcms++; + info++; + info->name = "STAC92xx Digital"; + if (spec->multiout.dig_out_nid) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; + } + if (spec->dig_in_nid) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; + } + } + return 0; } @@ -492,9 +592,12 @@ static int patch_stac9200(struct hda_codec *codec) spec->multiout.max_channels = 2; spec->multiout.num_dacs = 1; spec->multiout.dac_nids = stac9200_dac_nids; + spec->multiout.dig_out_nid = 0x05; + spec->dig_in_nid = 0x04; spec->adc_nids = stac9200_adc_nids; spec->mux_nids = stac9200_mux_nids; - spec->input_mux = &stac9200_input_mux; + spec->num_muxes = 1; + spec->input_mux.num_items = 0; spec->pstate_nids = stac9200_pstate_nids; spec->num_pstates = 3; spec->pin_nids = stac9200_pin_nids; @@ -525,11 +628,14 @@ static int patch_stac922x(struct hda_codec *codec) spec->multiout.max_channels = 2; spec->multiout.num_dacs = 4; spec->multiout.dac_nids = stac922x_dac_nids; + spec->multiout.dig_out_nid = 0x08; + spec->dig_in_nid = 0x09; spec->adc_nids = stac922x_adc_nids; spec->mux_nids = stac922x_mux_nids; - spec->input_mux = &stac922x_input_mux; + spec->num_muxes = 2; + spec->input_mux.num_items = 0; spec->pstate_nids = stac922x_pstate_nids; - spec->num_pstates = 7; + spec->num_pstates = 8; spec->pin_nids = stac922x_pin_nids; #ifdef STAC_TEST spec->pin_configs = stac922x_pin_configs; -- cgit v0.10.2 From b3e28ce98a22a4ecc8101128fe18665ab29d3236 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Jun 2005 11:54:50 +0200 Subject: [ALSA] Add dxs_support for Soltek SL-K8Tpro-939 VIA82xx driver Added dxs_support entry for Soltek SL-K8Tpro-939. Signed-off-by: Takashi Iwai diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 7e570a4..42c48f0 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2186,6 +2186,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ + { .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */ { } /* terminator */ }; struct dxs_whitelist *w; -- cgit v0.10.2 From 2b6b22f3815b2937f272d3666bd18665d3f7f5a8 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 18 Jun 2005 13:50:22 +0200 Subject: [ALSA] emu10k1: Add more card identification entries. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 77be072..a341e75 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -734,12 +734,90 @@ static emu_chip_details_t emu_chip_details[] = { .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102, + .driver = "EMU10K1", .name = "SBLive! [CT4620]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4670]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4780]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102, + .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4830]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4831]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102, .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4850]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4870]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4871]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102, + .driver = "EMU10K1", .name = "SBLive! Value [SB0060]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102, + .driver = "EMU10K1", .name = "SBLive! Value [SB0101]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102, + .driver = "EMU10K1", .name = "SBLive! Value [SB0103]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102, + .driver = "EMU10K1", .name = "SBLive! [SB0105]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .driver = "EMU10K1", .name = "SB Live [Unknown]", .id = "Live", -- cgit v0.10.2 From b53542073927878b18d642f6bf794adef6d45a18 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 22 Jun 2005 09:58:03 -0500 Subject: [PATCH] Fix extra double quote in IPV4 Kconfig Kconfig option had an extra double quote at the end of the line which was causing in warning when building. Signed-off-by: Kumar Gala Signed-off-by: Linus Torvalds diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 05107e0..567b03b 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -2,7 +2,7 @@ # IP configuration # choice - prompt "Choose IP: FIB lookup"" + prompt "Choose IP: FIB lookup" depends on INET default IP_FIB_HASH -- cgit v0.10.2 From 94eb7f4cefaf3ed8e97504ce4f3946bdb908e501 Mon Sep 17 00:00:00 2001 From: James Morris Date: Wed, 22 Jun 2005 12:55:42 -0400 Subject: [PATCH] Update my credits entry diff --git a/CREDITS b/CREDITS index 2993348..3b7a154 100644 --- a/CREDITS +++ b/CREDITS @@ -2380,9 +2380,10 @@ E: tmolina@cablespeed.com D: bug fixes, documentation, minor hackery N: James Morris -E: jmorris@intercode.com.au +E: jmorris@redhat.com W: http://www.intercode.com.au/jmorris/ -D: Netfilter, Linux Security Modules (LSM). +D: Netfilter, Linux Security Modules (LSM), SELinux, IPSec, +D: Crypto API, general networking, miscellaneous. S: PO Box 707 S: Spit Junction NSW 2088 S: Australia -- cgit v0.10.2 From e00d349e7781a92cf35b242259c9e5341a9661bb Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 22 Jun 2005 20:26:05 +0100 Subject: [PATCH] ARM: Move signal return code into vector page Move the signal return code into the vector page instead of placing it on the user mode stack, which will allow us to avoid flushing the instruction cache on signals, as well as eventually allowing non-exec stack. Signed-off-by: Russell King diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 931919f..07ddeed61 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -19,6 +19,7 @@ #include #include "ptrace.h" +#include "signal.h" #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -35,7 +36,7 @@ #define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE)) #define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) -static const unsigned long retcodes[4] = { +const unsigned long sigreturn_codes[4] = { SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN }; @@ -500,17 +501,25 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, if (ka->sa.sa_flags & SA_SIGINFO) idx += 2; - if (__put_user(retcodes[idx], rc)) + if (__put_user(sigreturn_codes[idx], rc)) return 1; - /* - * Ensure that the instruction cache sees - * the return code written onto the stack. - */ - flush_icache_range((unsigned long)rc, - (unsigned long)(rc + 1)); - - retcode = ((unsigned long)rc) + thumb; + if (cpsr & MODE32_BIT) { + /* + * 32-bit code can use the new high-page + * signal return code support. + */ + retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb; + } else { + /* + * Ensure that the instruction cache sees + * the return code written onto the stack. + */ + flush_icache_range((unsigned long)rc, + (unsigned long)(rc + 1)); + + retcode = ((unsigned long)rc) + thumb; + } } regs->ARM_r0 = usig; diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h new file mode 100644 index 0000000..91d26fa --- /dev/null +++ b/arch/arm/kernel/signal.h @@ -0,0 +1,12 @@ +/* + * linux/arch/arm/kernel/signal.h + * + * Copyright (C) 2005 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define KERN_SIGRETURN_CODE 0xffff0500 + +extern const unsigned long sigreturn_codes[4]; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 45d2a03..2fb0a4c 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -30,6 +30,7 @@ #include #include "ptrace.h" +#include "signal.h" const char *processor_modes[]= { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , @@ -683,6 +684,14 @@ void __init trap_init(void) memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start); memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start); memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz); + + /* + * Copy signal return handlers into the vector page, and + * set sigreturn to be a pointer to these. + */ + memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes, + sizeof(sigreturn_codes)); + flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); } -- cgit v0.10.2 From bdf042486a01aefaf29d74be1b4526daa70a5f0f Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 22 Jun 2005 20:58:29 +0100 Subject: [PATCH] ARM: Factor out common pmd_populate functionality Both pmd_populate variants set two pmd entries before ensuring that they are flushed from the cache. Separate this functionality into __pmd_populate(). Signed-off-by: Russell King diff --git a/include/asm-arm/pgalloc.h b/include/asm-arm/pgalloc.h index e814f81..bc18ff4 100644 --- a/include/asm-arm/pgalloc.h +++ b/include/asm-arm/pgalloc.h @@ -89,6 +89,13 @@ static inline void pte_free(struct page *pte) __free_page(pte); } +static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval) +{ + pmdp[0] = __pmd(pmdval); + pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t)); + flush_pmd_entry(pmdp); +} + /* * Populate the pmdp entry with a pointer to the pte. This pmd is part * of the mm address space. @@ -99,32 +106,19 @@ static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) { unsigned long pte_ptr = (unsigned long)ptep; - unsigned long pmdval; - - BUG_ON(mm != &init_mm); /* * The pmd must be loaded with the physical * address of the PTE table */ pte_ptr -= PTRS_PER_PTE * sizeof(void *); - pmdval = __pa(pte_ptr) | _PAGE_KERNEL_TABLE; - pmdp[0] = __pmd(pmdval); - pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t)); - flush_pmd_entry(pmdp); + __pmd_populate(pmdp, __pa(pte_ptr) | _PAGE_KERNEL_TABLE); } static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *ptep) { - unsigned long pmdval; - - BUG_ON(mm == &init_mm); - - pmdval = page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE; - pmdp[0] = __pmd(pmdval); - pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t)); - flush_pmd_entry(pmdp); + __pmd_populate(pmdp, page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE); } #endif -- cgit v0.10.2 From d05fdb0cec75415b2d9eb95748386e67414e49c3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:19 +0000 Subject: [PATCH] RPC: Fix a race with rpc_restart_call() If the task->tk_exit() wants to restart the RPC call after delaying then the current RPC code will clobber the timer by calling rpc_delete_timer() immediately after re-entering the loop in __rpc_execute(). Problem noticed by Oleg Nesterov Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index c06614d..cc298fa4 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -555,6 +555,30 @@ __rpc_atrun(struct rpc_task *task) } /* + * Helper that calls task->tk_exit if it exists and then returns + * true if we should exit __rpc_execute. + */ +static inline int __rpc_do_exit(struct rpc_task *task) +{ + if (task->tk_exit != NULL) { + lock_kernel(); + task->tk_exit(task); + unlock_kernel(); + /* If tk_action is non-null, we should restart the call */ + if (task->tk_action != NULL) { + if (!RPC_ASSASSINATED(task)) { + /* Release RPC slot and buffer memory */ + xprt_release(task); + rpc_free(task); + return 0; + } + printk(KERN_ERR "RPC: dead task tried to walk away.\n"); + } + } + return 1; +} + +/* * This is the RPC `scheduler' (or rather, the finite state machine). */ static int __rpc_execute(struct rpc_task *task) @@ -566,8 +590,7 @@ static int __rpc_execute(struct rpc_task *task) BUG_ON(RPC_IS_QUEUED(task)); - restarted: - while (1) { + for (;;) { /* * Garbage collection of pending timers... */ @@ -600,11 +623,12 @@ static int __rpc_execute(struct rpc_task *task) * by someone else. */ if (!RPC_IS_QUEUED(task)) { - if (!task->tk_action) + if (task->tk_action != NULL) { + lock_kernel(); + task->tk_action(task); + unlock_kernel(); + } else if (__rpc_do_exit(task)) break; - lock_kernel(); - task->tk_action(task); - unlock_kernel(); } /* @@ -645,23 +669,6 @@ static int __rpc_execute(struct rpc_task *task) dprintk("RPC: %4d sync task resuming\n", task->tk_pid); } - if (task->tk_exit) { - lock_kernel(); - task->tk_exit(task); - unlock_kernel(); - /* If tk_action is non-null, the user wants us to restart */ - if (task->tk_action) { - if (!RPC_ASSASSINATED(task)) { - /* Release RPC slot and buffer memory */ - if (task->tk_rqstp) - xprt_release(task); - rpc_free(task); - goto restarted; - } - printk(KERN_ERR "RPC: dead task tries to walk away.\n"); - } - } - dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status); status = task->tk_status; -- cgit v0.10.2 From 334ccfd545bba9690515f2c5c167d5adb161989b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:19 +0000 Subject: [PATCH] RPC: Ensure XDR iovec length is initialized correctly in call_header Fix up call_header() so that it calls xdr_adjust_iovec(). Fix calculation of the scratch buffer length in xdr_init_encode(). Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 02bc029..209aaf5 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -957,7 +957,9 @@ call_header(struct rpc_task *task) *p++ = htonl(clnt->cl_prog); /* program number */ *p++ = htonl(clnt->cl_vers); /* program version */ *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ - return rpcauth_marshcred(task, p); + p = rpcauth_marshcred(task, p); + req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); + return p; } /* diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index bb2d99f..a02d424 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -281,6 +281,7 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) rqstp->rq_res.len = 0; rqstp->rq_res.page_base = 0; rqstp->rq_res.page_len = 0; + rqstp->rq_res.buflen = PAGE_SIZE; rqstp->rq_res.tail[0].iov_len = 0; /* tcp needs a space for the record length... */ if (rqstp->rq_prot == IPPROTO_TCP) diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 67b9f035..f86d1ba 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -616,12 +616,24 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len) void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) { struct kvec *iov = buf->head; + int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len; + BUG_ON(scratch_len < 0); xdr->buf = buf; xdr->iov = iov; - xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); - buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base; - xdr->p = p; + xdr->p = (uint32_t *)((char *)iov->iov_base + iov->iov_len); + xdr->end = (uint32_t *)((char *)iov->iov_base + scratch_len); + BUG_ON(iov->iov_len > scratch_len); + + if (p != xdr->p && p != NULL) { + size_t len; + + BUG_ON(p < xdr->p || p > xdr->end); + len = (char *)p - (char *)xdr->p; + xdr->p = p; + buf->len += len; + iov->iov_len += len; + } } EXPORT_SYMBOL(xdr_init_encode); -- cgit v0.10.2 From 5b616f5d596c0b056129f8aeafbc08409b3cd050 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:20 +0000 Subject: [PATCH] RPC: Make rpc_create_client() destroy the transport on failure. This saves us a couple of lines of cleanup code for each call. Signed-off-by: Trond Myklebust diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 52707c5..90a62f2 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -193,10 +193,8 @@ nlm_bind_host(struct nlm_host *host) /* Existing NLM servers accept AUTH_UNIX only */ clnt = rpc_create_client(xprt, host->h_name, &nlm_program, host->h_version, RPC_AUTH_UNIX); - if (IS_ERR(clnt)) { - xprt_destroy(xprt); + if (IS_ERR(clnt)) goto forgetit; - } clnt->cl_autobind = 1; /* turn on pmap queries */ xprt->nocong = 1; /* No congestion control for NLM */ xprt->resvport = 1; /* NLM requires a reserved port */ diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 6fc1beb..81b5e77 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -120,15 +120,14 @@ nsm_create(void) &nsm_program, SM_VERSION, RPC_AUTH_NULL); if (IS_ERR(clnt)) - goto out_destroy; + goto out_err; clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clnt->cl_oneshot = 1; xprt->resvport = 1; /* NSM requires a reserved port */ return clnt; -out_destroy: - xprt_destroy(xprt); +out_err: return clnt; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f2317f3..ea78496 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -383,7 +383,6 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) return clnt; out_fail: - xprt_destroy(xprt); return clnt; } @@ -1623,7 +1622,6 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, if (IS_ERR(clnt)) { up_write(&clp->cl_sem); printk(KERN_WARNING "NFS: cannot create RPC client.\n"); - xprt_destroy(xprt); err = PTR_ERR(clnt); goto out_fail; } diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 9d3ddad..0e82617 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -80,9 +80,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, clnt = rpc_create_client(xprt, hostname, &mnt_program, version, RPC_AUTH_UNIX); - if (IS_ERR(clnt)) { - xprt_destroy(xprt); - } else { + if (!IS_ERR(clnt)) { clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clnt->cl_oneshot = 1; diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 1a55dfc..634465e 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -430,7 +430,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX); if (IS_ERR(clnt)) { dprintk("NFSD: couldn't create callback client\n"); - goto out_xprt; + goto out_err; } clnt->cl_intr = 0; clnt->cl_softrtry = 1; @@ -465,8 +465,6 @@ out_rpciod: out_clnt: rpc_shutdown_client(clnt); goto out_err; -out_xprt: - xprt_destroy(xprt); out_err: dprintk("NFSD: warning: no callback path to client %.*s\n", (int)clp->cl_name.len, clp->cl_name.data); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 209aaf5..99515d7 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -178,6 +178,7 @@ out_no_path: kfree(clnt->cl_server); kfree(clnt); out_err: + xprt_destroy(xprt); return ERR_PTR(err); } diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index d0b1d2c..97c420f 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -210,9 +210,7 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto) clnt = rpc_create_client(xprt, hostname, &pmap_program, RPC_PMAP_VERSION, RPC_AUTH_UNIX); - if (IS_ERR(clnt)) { - xprt_destroy(xprt); - } else { + if (!IS_ERR(clnt)) { clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clnt->cl_oneshot = 1; diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index d4f26bf..1b0ff7e 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -61,7 +61,6 @@ EXPORT_SYMBOL(rpc_mkpipe); /* Client transport */ EXPORT_SYMBOL(xprt_create_proto); -EXPORT_SYMBOL(xprt_destroy); EXPORT_SYMBOL(xprt_set_timeout); EXPORT_SYMBOL(xprt_udp_slot_table_entries); EXPORT_SYMBOL(xprt_tcp_slot_table_entries); -- cgit v0.10.2 From 5ee0ed7d3ab620a764740fb018f469d45f561931 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:20 +0000 Subject: [PATCH] RPC: Make rpc_create_client() probe server for RPC program+version support Ensure that we don't create an RPC client without checking that the server does indeed support the RPC program + version that we are trying to set up. This enables us to immediately return an error to "mount" if it turns out that the server is only supporting NFSv2, when we requested NFSv3 or NFSv4. Signed-off-by: Trond Myklebust diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 90a62f2..82c77df 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -189,6 +189,8 @@ nlm_bind_host(struct nlm_host *host) goto forgetit; xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); + xprt->nocong = 1; /* No congestion control for NLM */ + xprt->resvport = 1; /* NLM requires a reserved port */ /* Existing NLM servers accept AUTH_UNIX only */ clnt = rpc_create_client(xprt, host->h_name, &nlm_program, @@ -196,8 +198,6 @@ nlm_bind_host(struct nlm_host *host) if (IS_ERR(clnt)) goto forgetit; clnt->cl_autobind = 1; /* turn on pmap queries */ - xprt->nocong = 1; /* No congestion control for NLM */ - xprt->resvport = 1; /* NLM requires a reserved port */ host->h_rpcclnt = clnt; } diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 81b5e77..2d144ab 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -115,6 +115,7 @@ nsm_create(void) xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); if (IS_ERR(xprt)) return (struct rpc_clnt *)xprt; + xprt->resvport = 1; /* NSM requires a reserved port */ clnt = rpc_create_client(xprt, "localhost", &nsm_program, SM_VERSION, @@ -124,7 +125,6 @@ nsm_create(void) clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clnt->cl_oneshot = 1; - xprt->resvport = 1; /* NSM requires a reserved port */ return clnt; out_err: diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 2709caf..d25e80f 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -111,6 +111,9 @@ struct rpc_procinfo { struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, struct rpc_program *info, u32 version, rpc_authflavor_t authflavor); +struct rpc_clnt *rpc_new_client(struct rpc_xprt *xprt, char *servname, + struct rpc_program *info, + u32 version, rpc_authflavor_t authflavor); struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); int rpc_shutdown_client(struct rpc_clnt *); int rpc_destroy_client(struct rpc_clnt *); @@ -129,6 +132,7 @@ void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset); void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); size_t rpc_max_payload(struct rpc_clnt *); +int rpc_ping(struct rpc_clnt *clnt, int flags); static __inline__ int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 99515d7..b36797a 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -97,7 +97,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) * made to sleep too long. */ struct rpc_clnt * -rpc_create_client(struct rpc_xprt *xprt, char *servname, +rpc_new_client(struct rpc_xprt *xprt, char *servname, struct rpc_program *program, u32 vers, rpc_authflavor_t flavor) { @@ -182,6 +182,36 @@ out_err: return ERR_PTR(err); } +/** + * Create an RPC client + * @xprt - pointer to xprt struct + * @servname - name of server + * @info - rpc_program + * @version - rpc_program version + * @authflavor - rpc_auth flavour to use + * + * Creates an RPC client structure, then pings the server in order to + * determine if it is up, and if it supports this program and version. + * + * This function should never be called by asynchronous tasks such as + * the portmapper. + */ +struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, + struct rpc_program *info, u32 version, rpc_authflavor_t authflavor) +{ + struct rpc_clnt *clnt; + int err; + + clnt = rpc_new_client(xprt, servname, info, version, authflavor); + if (IS_ERR(clnt)) + return clnt; + err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR); + if (err == 0) + return clnt; + rpc_shutdown_client(clnt); + return ERR_PTR(err); +} + /* * This function clones the RPC client structure. It allows us to share the * same transport while varying parameters such as the authentication @@ -1086,3 +1116,30 @@ out_overflow: printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__); goto out_retry; } + +static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj) +{ + return 0; +} + +static int rpcproc_decode_null(void *rqstp, u32 *data, void *obj) +{ + return 0; +} + +static struct rpc_procinfo rpcproc_null = { + .p_encode = rpcproc_encode_null, + .p_decode = rpcproc_decode_null, +}; + +int rpc_ping(struct rpc_clnt *clnt, int flags) +{ + struct rpc_message msg = { + .rpc_proc = &rpcproc_null, + }; + int err; + msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0); + err = rpc_call_sync(clnt, &msg, flags); + put_rpccred(msg.rpc_cred); + return err; +} diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index 97c420f..df4d84c 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -207,7 +207,7 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto) xprt->addr.sin_port = htons(RPC_PMAP_PORT); /* printk("pmap: create clnt\n"); */ - clnt = rpc_create_client(xprt, hostname, + clnt = rpc_new_client(xprt, hostname, &pmap_program, RPC_PMAP_VERSION, RPC_AUTH_UNIX); if (!IS_ERR(clnt)) { -- cgit v0.10.2 From 9085bbcb76421a90bea28f4d3d03fa9977319c49 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:20 +0000 Subject: [PATCH] NFS: Kill annoying mount version mismatch printks Ensure that we fix up the missing fields in the nfs_mount_data with sane defaults for older versions of mount, and return errors in the cases where we cannot. Convert a bunch of annoying warnings into dprintks() Return -EPROTONOSUPPORT rather than EIO if mount() tries to set NFSv3 without it actually being compiled in. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index ea78496..32ddcf6 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -366,13 +366,15 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP, &server->addr, &timeparms); if (IS_ERR(xprt)) { - printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); + dprintk("%s: cannot create RPC transport. Error = %ld\n", + __FUNCTION__, PTR_ERR(xprt)); return (struct rpc_clnt *)xprt; } clnt = rpc_create_client(xprt, server->hostname, &nfs_program, server->rpc_ops->version, data->pseudoflavor); if (IS_ERR(clnt)) { - printk(KERN_WARNING "NFS: cannot create RPC client.\n"); + dprintk("%s: cannot create RPC client. Error = %ld\n", + __FUNCTION__, PTR_ERR(xprt)); goto out_fail; } @@ -426,21 +428,16 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) /* Check NFS protocol revision and initialize RPC op vector * and file handle pool. */ - if (server->flags & NFS_MOUNT_VER3) { #ifdef CONFIG_NFS_V3 + if (server->flags & NFS_MOUNT_VER3) { server->rpc_ops = &nfs_v3_clientops; server->caps |= NFS_CAP_READDIRPLUS; - if (data->version < 4) { - printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n"); - return -EIO; - } -#else - printk(KERN_NOTICE "NFS: NFSv3 not supported.\n"); - return -EIO; -#endif } else { server->rpc_ops = &nfs_v2_clientops; } +#else + server->rpc_ops = &nfs_v2_clientops; +#endif /* Fill in pseudoflavor for mount version < 5 */ if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) @@ -1384,74 +1381,94 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data) { int error; - struct nfs_server *server; + struct nfs_server *server = NULL; struct super_block *s; struct nfs_fh *root; struct nfs_mount_data *data = raw_data; - if (!data) { - printk("nfs_read_super: missing data argument\n"); - return ERR_PTR(-EINVAL); + s = ERR_PTR(-EINVAL); + if (data == NULL) { + dprintk("%s: missing data argument\n", __FUNCTION__); + goto out_err; + } + if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { + dprintk("%s: bad mount version\n", __FUNCTION__); + goto out_err; } + switch (data->version) { + case 1: + data->namlen = 0; + case 2: + data->bsize = 0; + case 3: + if (data->flags & NFS_MOUNT_VER3) { + dprintk("%s: mount structure version %d does not support NFSv3\n", + __FUNCTION__, + data->version); + goto out_err; + } + data->root.size = NFS2_FHSIZE; + memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); + case 4: + if (data->flags & NFS_MOUNT_SECFLAVOUR) { + dprintk("%s: mount structure version %d does not support strong security\n", + __FUNCTION__, + data->version); + goto out_err; + } + case 5: + memset(data->context, 0, sizeof(data->context)); + } +#ifndef CONFIG_NFS_V3 + /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ + s = ERR_PTR(-EPROTONOSUPPORT); + if (data->flags & NFS_MOUNT_VER3) { + dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); + goto out_err; + } +#endif /* CONFIG_NFS_V3 */ + s = ERR_PTR(-ENOMEM); server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); if (!server) - return ERR_PTR(-ENOMEM); + goto out_err; memset(server, 0, sizeof(struct nfs_server)); /* Zero out the NFS state stuff */ init_nfsv4_state(server); - if (data->version != NFS_MOUNT_VERSION) { - printk("nfs warning: mount version %s than kernel\n", - data->version < NFS_MOUNT_VERSION ? "older" : "newer"); - if (data->version < 2) - data->namlen = 0; - if (data->version < 3) - data->bsize = 0; - if (data->version < 4) { - data->flags &= ~NFS_MOUNT_VER3; - data->root.size = NFS2_FHSIZE; - memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); - } - if (data->version < 5) - data->flags &= ~NFS_MOUNT_SECFLAVOUR; - } - root = &server->fh; if (data->flags & NFS_MOUNT_VER3) root->size = data->root.size; else root->size = NFS2_FHSIZE; + s = ERR_PTR(-EINVAL); if (root->size > sizeof(root->data)) { - printk("nfs_get_sb: invalid root filehandle\n"); - kfree(server); - return ERR_PTR(-EINVAL); + dprintk("%s: invalid root filehandle\n", __FUNCTION__); + goto out_err; } memcpy(root->data, data->root.data, root->size); /* We now require that the mount process passes the remote address */ memcpy(&server->addr, &data->addr, sizeof(server->addr)); if (server->addr.sin_addr.s_addr == INADDR_ANY) { - printk("NFS: mount program didn't pass remote address!\n"); - kfree(server); - return ERR_PTR(-EINVAL); + dprintk("%s: mount program didn't pass remote address!\n", + __FUNCTION__); + goto out_err; } - s = sget(fs_type, nfs_compare_super, nfs_set_super, server); - - if (IS_ERR(s) || s->s_root) { - kfree(server); - return s; + /* Fire up rpciod if not yet running */ + s = ERR_PTR(rpciod_up()); + if (IS_ERR(s)) { + dprintk("%s: couldn't start rpciod! Error = %ld\n", + __FUNCTION__, PTR_ERR(s)); + goto out_err; } - s->s_flags = flags; + s = sget(fs_type, nfs_compare_super, nfs_set_super, server); + if (IS_ERR(s) || s->s_root) + goto out_rpciod_down; - /* Fire up rpciod if not yet running */ - if (rpciod_up() != 0) { - printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); - kfree(server); - return ERR_PTR(-EIO); - } + s->s_flags = flags; error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); if (error) { @@ -1461,6 +1478,11 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, } s->s_flags |= MS_ACTIVE; return s; +out_rpciod_down: + rpciod_down(); +out_err: + kfree(server); + return s; } static void nfs_kill_super(struct super_block *s) @@ -1593,15 +1615,19 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, clp = nfs4_get_client(&server->addr.sin_addr); if (!clp) { - printk(KERN_WARNING "NFS: failed to create NFS4 client.\n"); + dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); return -EIO; } /* Now create transport and client */ authflavour = RPC_AUTH_UNIX; if (data->auth_flavourlen != 0) { - if (data->auth_flavourlen > 1) - printk(KERN_INFO "NFS: cannot yet deal with multiple auth flavours.\n"); + if (data->auth_flavourlen != 1) { + dprintk("%s: Invalid number of RPC auth flavours %d.\n", + __FUNCTION__, data->auth_flavourlen); + err = -EINVAL; + goto out_fail; + } if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) { err = -EFAULT; goto out_fail; @@ -1613,16 +1639,18 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, xprt = xprt_create_proto(proto, &server->addr, &timeparms); if (IS_ERR(xprt)) { up_write(&clp->cl_sem); - printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); err = PTR_ERR(xprt); + dprintk("%s: cannot create RPC transport. Error = %d\n", + __FUNCTION__, err); goto out_fail; } clnt = rpc_create_client(xprt, server->hostname, &nfs_program, server->rpc_ops->version, authflavour); if (IS_ERR(clnt)) { up_write(&clp->cl_sem); - printk(KERN_WARNING "NFS: cannot create RPC client.\n"); err = PTR_ERR(clnt); + dprintk("%s: cannot create RPC client. Error = %d\n", + __FUNCTION__, err); goto out_fail; } clnt->cl_intr = 1; @@ -1654,20 +1682,22 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, clp = NULL; if (IS_ERR(clnt)) { - printk(KERN_WARNING "NFS: cannot create RPC client.\n"); - return PTR_ERR(clnt); + err = PTR_ERR(clnt); + dprintk("%s: cannot create RPC client. Error = %d\n", + __FUNCTION__, err); + return err; } server->client = clnt; if (server->nfs4_state->cl_idmap == NULL) { - printk(KERN_WARNING "NFS: failed to create idmapper.\n"); + dprintk("%s: failed to create idmapper.\n", __FUNCTION__); return -ENOMEM; } if (clnt->cl_auth->au_flavor != authflavour) { if (rpcauth_create(authflavour, clnt) == NULL) { - printk(KERN_WARNING "NFS: couldn't create credcache!\n"); + dprintk("%s: couldn't create credcache!\n", __FUNCTION__); return -ENOMEM; } } @@ -1728,8 +1758,12 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, struct nfs4_mount_data *data = raw_data; void *p; - if (!data) { - printk("nfs_read_super: missing data argument\n"); + if (data == NULL) { + dprintk("%s: missing data argument\n", __FUNCTION__); + return ERR_PTR(-EINVAL); + } + if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) { + dprintk("%s: bad mount version\n", __FUNCTION__); return ERR_PTR(-EINVAL); } @@ -1740,11 +1774,6 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, /* Zero out the NFS state stuff */ init_nfsv4_state(server); - if (data->version != NFS4_MOUNT_VERSION) { - printk("nfs warning: mount version %s than kernel\n", - data->version < NFS4_MOUNT_VERSION ? "older" : "newer"); - } - p = nfs_copy_user_string(NULL, &data->hostname, 256); if (IS_ERR(p)) goto out_err; @@ -1771,11 +1800,20 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, } if (server->addr.sin_family != AF_INET || server->addr.sin_addr.s_addr == INADDR_ANY) { - printk("NFS: mount program didn't pass remote IP address!\n"); + dprintk("%s: mount program didn't pass remote IP address!\n", + __FUNCTION__); s = ERR_PTR(-EINVAL); goto out_free; } + /* Fire up rpciod if not yet running */ + s = ERR_PTR(rpciod_up()); + if (IS_ERR(s)) { + dprintk("%s: couldn't start rpciod! Error = %ld\n", + __FUNCTION__, PTR_ERR(s)); + goto out_free; + } + s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); if (IS_ERR(s) || s->s_root) @@ -1783,13 +1821,6 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, s->s_flags = flags; - /* Fire up rpciod if not yet running */ - if (rpciod_up() != 0) { - printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); - s = ERR_PTR(-EIO); - goto out_free; - } - error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); if (error) { up_write(&s->s_umount); -- cgit v0.10.2 From 4ce79717ce32a9f88c1ddce4b9658556cb59d37a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:21 +0000 Subject: [PATCH] NFS: Header file cleanup... - Move NFSv4 state definitions into a private header file. - Clean up gunk in nfs_fs.h Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 560d617..f2ca782 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -14,6 +14,7 @@ #include #include #include +#include "nfs4_fs.h" #include "callback.h" #define NFSDBG_FACILITY NFSDBG_CALLBACK diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index ece27e4..65f1e19 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -8,6 +8,7 @@ #include #include #include +#include "nfs4_fs.h" #include "callback.h" #include "delegation.h" diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index d271df9..c99677e 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -10,6 +10,7 @@ #include #include #include +#include "nfs4_fs.h" #include "callback.h" #define CB_OP_TAGLEN_MAXSZ (512) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 5b9c60f..d7f7eb6 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -16,6 +16,7 @@ #include #include +#include "nfs4_fs.h" #include "delegation.h" static struct nfs_delegation *nfs_alloc_delegation(void) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ff6155f..9ccb15e8 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -32,6 +32,7 @@ #include #include +#include "nfs4_fs.h" #include "delegation.h" #define NFS_PARANOIA 1 diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 87f4f9a..ffb8df9 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -50,6 +50,7 @@ #include #include +#include "nfs4_fs.h" #define IDMAP_HASH_SZ 128 diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 32ddcf6..c80a81f 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -39,6 +39,7 @@ #include #include +#include "nfs4_fs.h" #include "delegation.h" #define NFSDBG_FACILITY NFSDBG_VFS diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h new file mode 100644 index 0000000..85cf3bd --- /dev/null +++ b/fs/nfs/nfs4_fs.h @@ -0,0 +1,250 @@ +/* + * linux/fs/nfs/nfs4_fs.h + * + * Copyright (C) 2005 Trond Myklebust + * + * NFSv4-specific filesystem definitions and declarations + */ + +#ifndef __LINUX_FS_NFS_NFS4_FS_H +#define __LINUX_FS_NFS_NFS4_FS_H + +#ifdef CONFIG_NFS_V4 + +struct idmap; + +/* + * In a seqid-mutating op, this macro controls which error return + * values trigger incrementation of the seqid. + * + * from rfc 3010: + * The client MUST monotonically increment the sequence number for the + * CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE + * operations. This is true even in the event that the previous + * operation that used the sequence number received an error. The only + * exception to this rule is if the previous operation received one of + * the following errors: NFSERR_STALE_CLIENTID, NFSERR_STALE_STATEID, + * NFSERR_BAD_STATEID, NFSERR_BAD_SEQID, NFSERR_BADXDR, + * NFSERR_RESOURCE, NFSERR_NOFILEHANDLE. + * + */ +#define seqid_mutating_err(err) \ +(((err) != NFSERR_STALE_CLIENTID) && \ + ((err) != NFSERR_STALE_STATEID) && \ + ((err) != NFSERR_BAD_STATEID) && \ + ((err) != NFSERR_BAD_SEQID) && \ + ((err) != NFSERR_BAD_XDR) && \ + ((err) != NFSERR_RESOURCE) && \ + ((err) != NFSERR_NOFILEHANDLE)) + +enum nfs4_client_state { + NFS4CLNT_OK = 0, +}; + +/* + * The nfs4_client identifies our client state to the server. + */ +struct nfs4_client { + struct list_head cl_servers; /* Global list of servers */ + struct in_addr cl_addr; /* Server identifier */ + u64 cl_clientid; /* constant */ + nfs4_verifier cl_confirm; + unsigned long cl_state; + + u32 cl_lockowner_id; + + /* + * The following rwsem ensures exclusive access to the server + * while we recover the state following a lease expiration. + */ + struct rw_semaphore cl_sem; + + struct list_head cl_delegations; + struct list_head cl_state_owners; + struct list_head cl_unused; + int cl_nunused; + spinlock_t cl_lock; + atomic_t cl_count; + + struct rpc_clnt * cl_rpcclient; + struct rpc_cred * cl_cred; + + struct list_head cl_superblocks; /* List of nfs_server structs */ + + unsigned long cl_lease_time; + unsigned long cl_last_renewal; + struct work_struct cl_renewd; + struct work_struct cl_recoverd; + + wait_queue_head_t cl_waitq; + struct rpc_wait_queue cl_rpcwaitq; + + /* used for the setclientid verifier */ + struct timespec cl_boot_time; + + /* idmapper */ + struct idmap * cl_idmap; + + /* Our own IP address, as a null-terminated string. + * This is used to generate the clientid, and the callback address. + */ + char cl_ipaddr[16]; + unsigned char cl_id_uniquifier; +}; + +/* + * NFS4 state_owners and lock_owners are simply labels for ordered + * sequences of RPC calls. Their sole purpose is to provide once-only + * semantics by allowing the server to identify replayed requests. + * + * The ->so_sema is held during all state_owner seqid-mutating operations: + * OPEN, OPEN_DOWNGRADE, and CLOSE. Its purpose is to properly serialize + * so_seqid. + */ +struct nfs4_state_owner { + struct list_head so_list; /* per-clientid list of state_owners */ + struct nfs4_client *so_client; + u32 so_id; /* 32-bit identifier, unique */ + struct semaphore so_sema; + u32 so_seqid; /* protected by so_sema */ + atomic_t so_count; + + struct rpc_cred *so_cred; /* Associated cred */ + struct list_head so_states; + struct list_head so_delegations; +}; + +/* + * struct nfs4_state maintains the client-side state for a given + * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). + * + * OPEN: + * In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server, + * we need to know how many files are open for reading or writing on a + * given inode. This information too is stored here. + * + * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) + */ + +struct nfs4_lock_state { + struct list_head ls_locks; /* Other lock stateids */ + fl_owner_t ls_owner; /* POSIX lock owner */ +#define NFS_LOCK_INITIALIZED 1 + int ls_flags; + u32 ls_seqid; + u32 ls_id; + nfs4_stateid ls_stateid; + atomic_t ls_count; +}; + +/* bits for nfs4_state->flags */ +enum { + LK_STATE_IN_USE, + NFS_DELEGATED_STATE, +}; + +struct nfs4_state { + struct list_head open_states; /* List of states for the same state_owner */ + struct list_head inode_states; /* List of states for the same inode */ + struct list_head lock_states; /* List of subservient lock stateids */ + + struct nfs4_state_owner *owner; /* Pointer to the open owner */ + struct inode *inode; /* Pointer to the inode */ + + unsigned long flags; /* Do we hold any locks? */ + struct semaphore lock_sema; /* Serializes file locking operations */ + rwlock_t state_lock; /* Protects the lock_states list */ + + nfs4_stateid stateid; + + unsigned int nreaders; + unsigned int nwriters; + int state; /* State on the server (R,W, or RW) */ + atomic_t count; +}; + + +struct nfs4_exception { + long timeout; + int retry; +}; + +struct nfs4_state_recovery_ops { + int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); + int (*recover_lock)(struct nfs4_state *, struct file_lock *); +}; + +extern struct dentry_operations nfs4_dentry_operations; +extern struct inode_operations nfs4_dir_inode_operations; + +/* nfs4proc.c */ +extern int nfs4_map_errors(int err); +extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short); +extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); +extern int nfs4_proc_async_renew(struct nfs4_client *); +extern int nfs4_proc_renew(struct nfs4_client *); +extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode); +extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); +extern int nfs4_open_revalidate(struct inode *, struct dentry *, int); + +extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; +extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; + +extern const u32 nfs4_fattr_bitmap[2]; +extern const u32 nfs4_statfs_bitmap[2]; +extern const u32 nfs4_pathconf_bitmap[2]; +extern const u32 nfs4_fsinfo_bitmap[2]; + +/* nfs4renewd.c */ +extern void nfs4_schedule_state_renewal(struct nfs4_client *); +extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); +extern void nfs4_kill_renewd(struct nfs4_client *); +extern void nfs4_renew_state(void *); + +/* nfs4state.c */ +extern void init_nfsv4_state(struct nfs_server *); +extern void destroy_nfsv4_state(struct nfs_server *); +extern struct nfs4_client *nfs4_get_client(struct in_addr *); +extern void nfs4_put_client(struct nfs4_client *clp); +extern int nfs4_init_client(struct nfs4_client *clp); +extern struct nfs4_client *nfs4_find_client(struct in_addr *); +extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); + +extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); +extern void nfs4_put_state_owner(struct nfs4_state_owner *); +extern void nfs4_drop_state_owner(struct nfs4_state_owner *); +extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); +extern void nfs4_put_open_state(struct nfs4_state *); +extern void nfs4_close_state(struct nfs4_state *, mode_t); +extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); +extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); +extern void nfs4_schedule_state_recovery(struct nfs4_client *); +extern struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t); +extern struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t); +extern void nfs4_put_lock_state(struct nfs4_lock_state *state); +extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls); +extern void nfs4_notify_setlk(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *); +extern void nfs4_notify_unlck(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *); +extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); + +extern const nfs4_stateid zero_stateid; + +/* nfs4xdr.c */ +extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus); +extern struct rpc_procinfo nfs4_procedures[]; + +struct nfs4_mount_data; + +/* callback_xdr.c */ +extern struct svc_version nfs4_callback_version1; + +#else + +#define init_nfsv4_state(server) do { } while (0) +#define destroy_nfsv4_state(server) do { } while (0) +#define nfs4_put_state_owner(inode, owner) do { } while (0) +#define nfs4_put_open_state(state) do { } while (0) +#define nfs4_close_state(a, b) do { } while (0) + +#endif /* CONFIG_NFS_V4 */ +#endif /* __LINUX_FS_NFS_NFS4_FS.H */ diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1d5cb3e..a69c02b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -48,6 +48,7 @@ #include #include +#include "nfs4_fs.h" #include "delegation.h" #define NFSDBG_FACILITY NFSDBG_PROC @@ -62,8 +63,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; -extern nfs4_stateid zero_stateid; - /* Prevent leaks of NFSv4 errors into userland */ int nfs4_map_errors(int err) { @@ -104,7 +103,7 @@ const u32 nfs4_statfs_bitmap[2] = { | FATTR4_WORD1_SPACE_TOTAL }; -u32 nfs4_pathconf_bitmap[2] = { +const u32 nfs4_pathconf_bitmap[2] = { FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME, 0 diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 667e06f..a300162 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c @@ -53,6 +53,7 @@ #include #include #include +#include "nfs4_fs.h" #define NFSDBG_FACILITY NFSDBG_PROC diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 231cebc..17b187f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -46,24 +46,18 @@ #include #include +#include "nfs4_fs.h" #include "callback.h" #include "delegation.h" #define OPENOWNER_POOL_SIZE 8 -static DEFINE_SPINLOCK(state_spinlock); - -nfs4_stateid zero_stateid; - -#if 0 -nfs4_stateid one_stateid = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -#endif +const nfs4_stateid zero_stateid; +static DEFINE_SPINLOCK(state_spinlock); static LIST_HEAD(nfs4_clientid_list); static void nfs4_recover_state(void *); -extern void nfs4_renew_state(void *); void init_nfsv4_state(struct nfs_server *server) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5f4de05..e86406e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -51,6 +51,7 @@ #include #include #include +#include "nfs4_fs.h" #define NFSDBG_FACILITY NFSDBG_XDR @@ -660,8 +661,6 @@ static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1 static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) { - extern u32 nfs4_fattr_bitmap[]; - return encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0], bitmask[1] & nfs4_fattr_bitmap[1]); @@ -669,8 +668,6 @@ static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) { - extern u32 nfs4_fsinfo_bitmap[]; - return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], bitmask[1] & nfs4_fsinfo_bitmap[1]); } @@ -969,7 +966,6 @@ static int encode_putrootfh(struct xdr_stream *xdr) static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) { - extern nfs4_stateid zero_stateid; nfs4_stateid stateid; uint32_t *p; @@ -1697,7 +1693,6 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs */ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args) { - extern u32 nfs4_pathconf_bitmap[2]; struct xdr_stream xdr; struct compound_hdr hdr = { .nops = 2, @@ -1718,7 +1713,6 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct */ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args) { - extern u32 nfs4_statfs_bitmap[]; struct xdr_stream xdr; struct compound_hdr hdr = { .nops = 2, diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index dbac7f3..fb33e76 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -15,7 +15,6 @@ #include #include #include -#include #include @@ -29,7 +28,6 @@ #include #include #include -#include #include /* @@ -44,13 +42,6 @@ #define NFS_DEF_FILE_IO_BUFFER_SIZE 4096 /* - * The upper limit on timeouts for the exponential backoff algorithm. - */ -#define NFS_WRITEBACK_DELAY (5*HZ) -#define NFS_WRITEBACK_LOCKDELAY (60*HZ) -#define NFS_COMMIT_DELAY (5*HZ) - -/* * superblock magic number for NFS */ #define NFS_SUPER_MAGIC 0x6969 @@ -60,9 +51,6 @@ */ #define NFS_RPC_SWAPFLAGS (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS) -#define NFS_RW_SYNC 0x0001 /* O_SYNC handling */ -#define NFS_RW_SWAP 0x0002 /* This is a swap request */ - /* * When flushing a cluster of dirty pages, there can be different * strategies: @@ -434,11 +422,6 @@ static inline void nfs_writedata_free(struct nfs_write_data *p) mempool_free(p, nfs_wdata_mempool); } -/* Hack for future NFS swap support */ -#ifndef IS_SWAPFILE -# define IS_SWAPFILE(inode) (0) -#endif - /* * linux/fs/nfs/read.c */ @@ -515,230 +498,6 @@ extern void * nfs_root_data(void); #define NFS_JUKEBOX_RETRY_TIME (5 * HZ) -#ifdef CONFIG_NFS_V4 - -struct idmap; - -/* - * In a seqid-mutating op, this macro controls which error return - * values trigger incrementation of the seqid. - * - * from rfc 3010: - * The client MUST monotonically increment the sequence number for the - * CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE - * operations. This is true even in the event that the previous - * operation that used the sequence number received an error. The only - * exception to this rule is if the previous operation received one of - * the following errors: NFSERR_STALE_CLIENTID, NFSERR_STALE_STATEID, - * NFSERR_BAD_STATEID, NFSERR_BAD_SEQID, NFSERR_BADXDR, - * NFSERR_RESOURCE, NFSERR_NOFILEHANDLE. - * - */ -#define seqid_mutating_err(err) \ -(((err) != NFSERR_STALE_CLIENTID) && \ - ((err) != NFSERR_STALE_STATEID) && \ - ((err) != NFSERR_BAD_STATEID) && \ - ((err) != NFSERR_BAD_SEQID) && \ - ((err) != NFSERR_BAD_XDR) && \ - ((err) != NFSERR_RESOURCE) && \ - ((err) != NFSERR_NOFILEHANDLE)) - -enum nfs4_client_state { - NFS4CLNT_OK = 0, -}; - -/* - * The nfs4_client identifies our client state to the server. - */ -struct nfs4_client { - struct list_head cl_servers; /* Global list of servers */ - struct in_addr cl_addr; /* Server identifier */ - u64 cl_clientid; /* constant */ - nfs4_verifier cl_confirm; - unsigned long cl_state; - - u32 cl_lockowner_id; - - /* - * The following rwsem ensures exclusive access to the server - * while we recover the state following a lease expiration. - */ - struct rw_semaphore cl_sem; - - struct list_head cl_delegations; - struct list_head cl_state_owners; - struct list_head cl_unused; - int cl_nunused; - spinlock_t cl_lock; - atomic_t cl_count; - - struct rpc_clnt * cl_rpcclient; - struct rpc_cred * cl_cred; - - struct list_head cl_superblocks; /* List of nfs_server structs */ - - unsigned long cl_lease_time; - unsigned long cl_last_renewal; - struct work_struct cl_renewd; - struct work_struct cl_recoverd; - - wait_queue_head_t cl_waitq; - struct rpc_wait_queue cl_rpcwaitq; - - /* used for the setclientid verifier */ - struct timespec cl_boot_time; - - /* idmapper */ - struct idmap * cl_idmap; - - /* Our own IP address, as a null-terminated string. - * This is used to generate the clientid, and the callback address. - */ - char cl_ipaddr[16]; - unsigned char cl_id_uniquifier; -}; - -/* - * NFS4 state_owners and lock_owners are simply labels for ordered - * sequences of RPC calls. Their sole purpose is to provide once-only - * semantics by allowing the server to identify replayed requests. - * - * The ->so_sema is held during all state_owner seqid-mutating operations: - * OPEN, OPEN_DOWNGRADE, and CLOSE. Its purpose is to properly serialize - * so_seqid. - */ -struct nfs4_state_owner { - struct list_head so_list; /* per-clientid list of state_owners */ - struct nfs4_client *so_client; - u32 so_id; /* 32-bit identifier, unique */ - struct semaphore so_sema; - u32 so_seqid; /* protected by so_sema */ - atomic_t so_count; - - struct rpc_cred *so_cred; /* Associated cred */ - struct list_head so_states; - struct list_head so_delegations; -}; - -/* - * struct nfs4_state maintains the client-side state for a given - * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). - * - * OPEN: - * In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server, - * we need to know how many files are open for reading or writing on a - * given inode. This information too is stored here. - * - * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) - */ - -struct nfs4_lock_state { - struct list_head ls_locks; /* Other lock stateids */ - fl_owner_t ls_owner; /* POSIX lock owner */ -#define NFS_LOCK_INITIALIZED 1 - int ls_flags; - u32 ls_seqid; - u32 ls_id; - nfs4_stateid ls_stateid; - atomic_t ls_count; -}; - -/* bits for nfs4_state->flags */ -enum { - LK_STATE_IN_USE, - NFS_DELEGATED_STATE, -}; - -struct nfs4_state { - struct list_head open_states; /* List of states for the same state_owner */ - struct list_head inode_states; /* List of states for the same inode */ - struct list_head lock_states; /* List of subservient lock stateids */ - - struct nfs4_state_owner *owner; /* Pointer to the open owner */ - struct inode *inode; /* Pointer to the inode */ - - unsigned long flags; /* Do we hold any locks? */ - struct semaphore lock_sema; /* Serializes file locking operations */ - rwlock_t state_lock; /* Protects the lock_states list */ - - nfs4_stateid stateid; - - unsigned int nreaders; - unsigned int nwriters; - int state; /* State on the server (R,W, or RW) */ - atomic_t count; -}; - - -struct nfs4_exception { - long timeout; - int retry; -}; - -struct nfs4_state_recovery_ops { - int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); - int (*recover_lock)(struct nfs4_state *, struct file_lock *); -}; - -extern struct dentry_operations nfs4_dentry_operations; -extern struct inode_operations nfs4_dir_inode_operations; - -/* nfs4proc.c */ -extern int nfs4_map_errors(int err); -extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short); -extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); -extern int nfs4_proc_async_renew(struct nfs4_client *); -extern int nfs4_proc_renew(struct nfs4_client *); -extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode); -extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); -extern int nfs4_open_revalidate(struct inode *, struct dentry *, int); - -extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; -extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; - -/* nfs4renewd.c */ -extern void nfs4_schedule_state_renewal(struct nfs4_client *); -extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); -extern void nfs4_kill_renewd(struct nfs4_client *); - -/* nfs4state.c */ -extern void init_nfsv4_state(struct nfs_server *); -extern void destroy_nfsv4_state(struct nfs_server *); -extern struct nfs4_client *nfs4_get_client(struct in_addr *); -extern void nfs4_put_client(struct nfs4_client *clp); -extern int nfs4_init_client(struct nfs4_client *clp); -extern struct nfs4_client *nfs4_find_client(struct in_addr *); -extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); - -extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); -extern void nfs4_put_state_owner(struct nfs4_state_owner *); -extern void nfs4_drop_state_owner(struct nfs4_state_owner *); -extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); -extern void nfs4_put_open_state(struct nfs4_state *); -extern void nfs4_close_state(struct nfs4_state *, mode_t); -extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); -extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); -extern void nfs4_schedule_state_recovery(struct nfs4_client *); -extern struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t); -extern struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t); -extern void nfs4_put_lock_state(struct nfs4_lock_state *state); -extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls); -extern void nfs4_notify_setlk(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *); -extern void nfs4_notify_unlck(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *); -extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); - - - -struct nfs4_mount_data; -#else -#define init_nfsv4_state(server) do { } while (0) -#define destroy_nfsv4_state(server) do { } while (0) -#define nfs4_put_state_owner(inode, owner) do { } while (0) -#define nfs4_put_open_state(state) do { } while (0) -#define nfs4_close_state(a, b) do { } while (0) -#define nfs4_renewd_prepare_shutdown(server) do { } while (0) -#endif - #endif /* __KERNEL__ */ /* -- cgit v0.10.2 From a656db998785324a818005bcf71bae6dcbbb3cf5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:21 +0000 Subject: [PATCH] NFS: Remove unused NFS inode field readdir_timestamp. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 9ccb15e8..dffa21a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -165,12 +165,10 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; /* Ensure consistent page alignment of the data. * Note: assumes we have exclusive access to this mapping either - * throught inode->i_sem or some other mechanism. + * through inode->i_sem or some other mechanism. */ - if (page->index == 0) { - invalidate_inode_pages(inode->i_mapping); - NFS_I(inode)->readdir_timestamp = timestamp; - } + if (page->index == 0) + invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1); unlock_page(page); return 0; error: diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index fb33e76..68d5aae 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -128,7 +128,6 @@ struct nfs_inode { * * mtime != read_cache_mtime */ - unsigned long readdir_timestamp; unsigned long read_cache_jiffies; unsigned long attrtimeo; unsigned long attrtimeo_timestamp; -- cgit v0.10.2 From 96651ab341cde0fee940ec837f323d711cbfa7d5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:21 +0000 Subject: [PATCH] RPC: Shrink struct rpc_task by switching to wait_on_bit() Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 99d17ed..4d77e90 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -31,7 +31,6 @@ struct rpc_wait_queue; struct rpc_wait { struct list_head list; /* wait queue links */ struct list_head links; /* Links to related tasks */ - wait_queue_head_t waitq; /* sync: sleep on this q */ struct rpc_wait_queue * rpc_waitq; /* RPC wait queue we're on */ }; diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index cc298fa4..2d9eb7f 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -290,7 +290,7 @@ static void rpc_make_runnable(struct rpc_task *task) return; } } else - wake_up(&task->u.tk_wait.waitq); + wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); } /* @@ -578,6 +578,14 @@ static inline int __rpc_do_exit(struct rpc_task *task) return 1; } +static int rpc_wait_bit_interruptible(void *word) +{ + if (signal_pending(current)) + return -ERESTARTSYS; + schedule(); + return 0; +} + /* * This is the RPC `scheduler' (or rather, the finite state machine). */ @@ -648,22 +656,21 @@ static int __rpc_execute(struct rpc_task *task) /* sync task: sleep here */ dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid); - if (RPC_TASK_UNINTERRUPTIBLE(task)) { - __wait_event(task->u.tk_wait.waitq, !RPC_IS_QUEUED(task)); - } else { - __wait_event_interruptible(task->u.tk_wait.waitq, !RPC_IS_QUEUED(task), status); + /* Note: Caller should be using rpc_clnt_sigmask() */ + status = out_of_line_wait_on_bit(&task->tk_runstate, + RPC_TASK_QUEUED, rpc_wait_bit_interruptible, + TASK_INTERRUPTIBLE); + if (status == -ERESTARTSYS) { /* * When a sync task receives a signal, it exits with * -ERESTARTSYS. In order to catch any callbacks that * clean up after sleeping on some queue, we don't * break the loop here, but go around once more. */ - if (status == -ERESTARTSYS) { - dprintk("RPC: %4d got signal\n", task->tk_pid); - task->tk_flags |= RPC_TASK_KILLED; - rpc_exit(task, -ERESTARTSYS); - rpc_wake_up_task(task); - } + dprintk("RPC: %4d got signal\n", task->tk_pid); + task->tk_flags |= RPC_TASK_KILLED; + rpc_exit(task, -ERESTARTSYS); + rpc_wake_up_task(task); } rpc_set_running(task); dprintk("RPC: %4d sync task resuming\n", task->tk_pid); @@ -766,8 +773,6 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, rpc_action call /* Initialize workqueue for async tasks */ task->tk_workqueue = rpciod_workqueue; - if (!RPC_IS_ASYNC(task)) - init_waitqueue_head(&task->u.tk_wait.waitq); if (clnt) { atomic_inc(&clnt->cl_users); -- cgit v0.10.2 From 464a98bd70bae8c559cfc82af799faf44824ce64 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:21 +0000 Subject: [PATCH] NFS: cleanup: shrink struct nfs_open_context Remove the wait queue, and replace the functions that depended on it with wait_on_bit(). Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index c80a81f..a38d4b2 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -848,7 +848,6 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp ctx->state = NULL; ctx->lockowner = current->files; ctx->error = 0; - init_waitqueue_head(&ctx->waitq); } return ctx; } diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 4f1ba72..80777f9 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -107,7 +107,7 @@ void nfs_unlock_request(struct nfs_page *req) smp_mb__before_clear_bit(); clear_bit(PG_BUSY, &req->wb_flags); smp_mb__after_clear_bit(); - wake_up_all(&req->wb_context->waitq); + wake_up_bit(&req->wb_flags, PG_BUSY); nfs_release_request(req); } @@ -180,6 +180,17 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head) req->wb_list_head = head; } +static int nfs_wait_bit_interruptible(void *word) +{ + int ret = 0; + + if (signal_pending(current)) + ret = -ERESTARTSYS; + else + schedule(); + return ret; +} + /** * nfs_wait_on_request - Wait for a request to complete. * @req: request to wait upon. @@ -190,12 +201,22 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head) int nfs_wait_on_request(struct nfs_page *req) { - struct inode *inode = req->wb_context->dentry->d_inode; - struct rpc_clnt *clnt = NFS_CLIENT(inode); - - if (!NFS_WBACK_BUSY(req)) - return 0; - return nfs_wait_event(clnt, req->wb_context->waitq, !NFS_WBACK_BUSY(req)); + struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->dentry->d_inode); + sigset_t oldmask; + int ret = 0; + + if (!test_bit(PG_BUSY, &req->wb_flags)) + goto out; + /* + * Note: the call to rpc_clnt_sigmask() suffices to ensure that we + * are not interrupted if intr flag is not set + */ + rpc_clnt_sigmask(clnt, &oldmask); + ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY, + nfs_wait_bit_interruptible, TASK_INTERRUPTIBLE); + rpc_clnt_sigunmask(clnt, &oldmask); +out: + return ret; } /** diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 68d5aae..0b01b96 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -84,7 +84,6 @@ struct nfs_open_context { int error; struct list_head list; - wait_queue_head_t waitq; }; /* -- cgit v0.10.2 From 92cfc62cb8412c9563860b1bf70cd4701f03092e Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 22 Jun 2005 17:16:22 +0000 Subject: [PATCH] NFS: Allow NFS versions to support different sets of inode operations. ACL support will require supporting additional inode operations in v4 (getxattr, setxattr, listxattr). This patch allows different protocol versions to support different inode operations by adding a file_inode_ops to the nfs_rpc_ops (to match the existing dir_inode_ops). Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index a38d4b2..a82f034 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -686,7 +686,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) /* Why so? Because we want revalidate for devices/FIFOs, and * that's precisely what we have in nfs_file_inode_operations. */ - inode->i_op = &nfs_file_inode_operations; + inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops; if (S_ISREG(inode->i_mode)) { inode->i_fop = &nfs_file_operations; inode->i_data.a_ops = &nfs_file_aops; diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 3878494d..53953a7 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -826,6 +826,7 @@ struct nfs_rpc_ops nfs_v3_clientops = { .version = 3, /* protocol version */ .dentry_ops = &nfs_dentry_operations, .dir_inode_ops = &nfs_dir_inode_operations, + .file_inode_ops = &nfs_file_inode_operations, .getroot = nfs3_proc_get_root, .getattr = nfs3_proc_getattr, .setattr = nfs3_proc_setattr, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a69c02b..a5a8cb3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2746,6 +2746,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { .version = 4, /* protocol version */ .dentry_ops = &nfs4_dentry_operations, .dir_inode_ops = &nfs4_dir_inode_operations, + .file_inode_ops = &nfs_file_inode_operations, .getroot = nfs4_proc_get_root, .getattr = nfs4_proc_getattr, .setattr = nfs4_proc_setattr, diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index d31b4d6..cedf636 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -622,6 +622,7 @@ struct nfs_rpc_ops nfs_v2_clientops = { .version = 2, /* protocol version */ .dentry_ops = &nfs_dentry_operations, .dir_inode_ops = &nfs_dir_inode_operations, + .file_inode_ops = &nfs_file_inode_operations, .getroot = nfs_proc_get_root, .getattr = nfs_proc_getattr, .setattr = nfs_proc_setattr, diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 47037d9..5b45baf 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -667,6 +667,7 @@ struct nfs_rpc_ops { int version; /* Protocol version */ struct dentry_operations *dentry_ops; struct inode_operations *dir_inode_ops; + struct inode_operations *file_inode_ops; int (*getroot) (struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); -- cgit v0.10.2 From ada70d9425bcc5e376fef8591e4e76e204c0834c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:22 +0000 Subject: [PATCH] NFS: Add hooks to allow common NFS attribute code to clear cached acls Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index a82f034..c45bd52 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -64,6 +64,7 @@ static void nfs_clear_inode(struct inode *); static void nfs_umount_begin(struct super_block *); static int nfs_statfs(struct super_block *, struct kstatfs *); static int nfs_show_options(struct seq_file *, struct vfsmount *); +static void nfs_zap_acl_cache(struct inode *); static struct rpc_program nfs_program; @@ -153,6 +154,7 @@ nfs_clear_inode(struct inode *inode) nfs_wb_all(inode); BUG_ON (!list_empty(&nfsi->open_files)); + nfs_zap_acl_cache(inode); cred = nfsi->cache_access.cred; if (cred) put_rpccred(cred); @@ -587,9 +589,19 @@ nfs_zap_caches(struct inode *inode) memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) - nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS; + nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; else - nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS; + nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; +} + +static void nfs_zap_acl_cache(struct inode *inode) +{ + void (*clear_acl_cache)(struct inode *); + + clear_acl_cache = NFS_PROTO(inode)->clear_acl_cache; + if (clear_acl_cache != NULL) + clear_acl_cache(inode); + NFS_I(inode)->flags &= ~NFS_INO_INVALID_ACL; } /* @@ -789,7 +801,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) } } if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) - NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS; + NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; nfs_end_data_update(inode); unlock_kernel(); return error; @@ -1033,6 +1045,8 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) /* This ensures we revalidate dentries */ nfsi->cache_change_attribute++; } + if (flags & NFS_INO_INVALID_ACL) + nfs_zap_acl_cache(inode); dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); @@ -1183,7 +1197,7 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || inode->i_uid != fattr->uid || inode->i_gid != fattr->gid) - nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; + nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; /* Has the link count changed? */ if (inode->i_nlink != fattr->nlink) @@ -1292,16 +1306,21 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign #endif nfsi->change_attr = fattr->change_attr; if (!data_unstable) - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS; + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; } - memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); + /* If ctime has changed we should definitely clear access+acl caches */ + if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { + if (!data_unstable) + invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; + memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); + } memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || inode->i_uid != fattr->uid || inode->i_gid != fattr->gid) - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS; + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; inode->i_mode = fattr->mode; inode->i_nlink = fattr->nlink; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 0b01b96..140bdf4 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -189,6 +189,7 @@ struct nfs_inode { #define NFS_INO_INVALID_DATA 0x0010 /* cached data is invalid */ #define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */ #define NFS_INO_INVALID_ACCESS 0x0040 /* cached access cred invalid */ +#define NFS_INO_INVALID_ACL 0x0080 /* cached acls are invalid */ static inline struct nfs_inode *NFS_I(struct inode *inode) { diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 5b45baf..cf38db5 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -714,6 +714,7 @@ struct nfs_rpc_ops { int (*file_open) (struct inode *, struct file *); int (*file_release) (struct inode *, struct file *); int (*lock)(struct file *, int, struct file_lock *); + void (*clear_acl_cache)(struct inode *); }; /* -- cgit v0.10.2 From 6b3b5496d7b261d6c9202008dc528e52dbd11e57 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 22 Jun 2005 17:16:22 +0000 Subject: [PATCH] NFSv4: Add {get,set,list}xattr methods for nfs4 Add {get,set,list}xattr methods for nfs4. The new methods are no-ops, to be used by subsequent ACL patch. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index dffa21a..5720537 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -91,6 +91,9 @@ struct inode_operations nfs4_dir_inode_operations = { .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, + .getxattr = nfs4_getxattr, + .setxattr = nfs4_setxattr, + .listxattr = nfs4_listxattr, }; #endif /* CONFIG_NFS_V4 */ diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 85cf3bd..d71f416 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -176,6 +176,13 @@ struct nfs4_state_recovery_ops { extern struct dentry_operations nfs4_dentry_operations; extern struct inode_operations nfs4_dir_inode_operations; +extern struct inode_operations nfs4_file_inode_operations; + +/* inode.c */ +extern ssize_t nfs4_getxattr(struct dentry *, const char *, void *, size_t); +extern int nfs4_setxattr(struct dentry *, const char *, const void *, size_t, int); +extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); + /* nfs4proc.c */ extern int nfs4_map_errors(int err); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a5a8cb3..1b14d17 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2732,6 +2732,34 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) return status; } + +int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, + size_t buflen, int flags) +{ + return -EOPNOTSUPP; +} + +/* The getxattr man page suggests returning -ENODATA for unknown attributes, + * and that's what we'll do for e.g. user attributes that haven't been set. + * But we'll follow ext2/ext3's lead by returning -EOPNOTSUPP for unsupported + * attributes in kernel-managed attribute namespaces. */ +ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf, + size_t buflen) +{ + return -EOPNOTSUPP; +} + +ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) +{ + ssize_t len = 0; + + if (buf && buflen < len) + return -ERANGE; + if (buf) + memcpy(buf, "", 0); + return 0; +} + struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { .recover_open = nfs4_open_reclaim, .recover_lock = nfs4_lock_reclaim, @@ -2742,11 +2770,20 @@ struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = { .recover_lock = nfs4_lock_expired, }; +static struct inode_operations nfs4_file_inode_operations = { + .permission = nfs_permission, + .getattr = nfs_getattr, + .setattr = nfs_setattr, + .getxattr = nfs4_getxattr, + .setxattr = nfs4_setxattr, + .listxattr = nfs4_listxattr, +}; + struct nfs_rpc_ops nfs_v4_clientops = { .version = 4, /* protocol version */ .dentry_ops = &nfs4_dentry_operations, .dir_inode_ops = &nfs4_dir_inode_operations, - .file_inode_ops = &nfs_file_inode_operations, + .file_inode_ops = &nfs4_file_inode_operations, .getroot = nfs4_proc_get_root, .getattr = nfs4_proc_getattr, .setattr = nfs4_proc_setattr, -- cgit v0.10.2 From 96928206961be05f22c3839f0097b610cc485b5d Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 22 Jun 2005 17:16:22 +0000 Subject: [PATCH] NFSv4: fix fattr size calculations Make nfs4 fattr size calculations more explicit, revising them downward a bit in the process. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e86406e..8204926 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -83,12 +83,16 @@ static int nfs_stat_to_errno(int); #define encode_getfh_maxsz (op_encode_hdr_maxsz) #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ ((3+NFS4_FHSIZE) >> 2)) -#define encode_getattr_maxsz (op_encode_hdr_maxsz + 3) +#define nfs4_fattr_bitmap_maxsz 3 +#define encode_getattr_maxsz (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) -#define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz) -#define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \ - nfs4_fattr_bitmap_maxsz) +/* This is based on getfattr, which uses the most attributes: */ +#define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \ + 3 + 3 + 3 + 2 * nfs4_name_maxsz)) +#define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ + nfs4_fattr_value_maxsz) +#define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) #define encode_savefh_maxsz (op_encode_hdr_maxsz) #define decode_savefh_maxsz (op_decode_hdr_maxsz) #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) @@ -123,11 +127,11 @@ static int nfs_stat_to_errno(int); #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ 1 + nfs4_name_maxsz + \ nfs4_path_maxsz + \ - nfs4_fattr_bitmap_maxsz) + nfs4_fattr_maxsz) #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) #define encode_create_maxsz (op_encode_hdr_maxsz + \ 2 + nfs4_name_maxsz + \ - nfs4_fattr_bitmap_maxsz) + nfs4_fattr_maxsz) #define decode_create_maxsz (op_decode_hdr_maxsz + 8) #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) @@ -206,7 +210,7 @@ static int nfs_stat_to_errno(int); #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ op_encode_hdr_maxsz + 4 + \ - nfs4_fattr_bitmap_maxsz + \ + nfs4_fattr_maxsz + \ encode_getattr_maxsz) #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ -- cgit v0.10.2 From 029d105e66e5a90850d5a09dad76815d0bcfcaa3 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 22 Jun 2005 17:16:22 +0000 Subject: [PATCH] NFSv4: Client-side xdr for reading NFSv4 acls Client-side support for NFSv4 acls: xdr encoding and decoding routines for reading acls Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 8204926..6f1c003 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -365,6 +365,13 @@ static int nfs_stat_to_errno(int); encode_delegreturn_maxsz) #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ decode_delegreturn_maxsz) +#define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + \ + nfs4_fattr_bitmap_maxsz + 1) static struct { unsigned int mode; @@ -1632,6 +1639,34 @@ out: } /* + * Encode a GETACL request + */ +static int +nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p, + struct nfs_getaclargs *args) +{ + struct xdr_stream xdr; + struct rpc_auth *auth = req->rq_task->tk_auth; + struct compound_hdr hdr = { + .nops = 2, + }; + int replen, status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if (status) + goto out; + status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0); + /* set up reply buffer: */ + replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; + xdr_inline_pages(&req->rq_rcv_buf, replen, + args->acl_pages, args->acl_pgbase, args->acl_len); +out: + return status; +} + +/* * Encode a WRITE request */ static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) @@ -3125,6 +3160,47 @@ static int decode_renew(struct xdr_stream *xdr) return decode_op_hdr(xdr, OP_RENEW); } +static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, + size_t *acl_len) +{ + uint32_t *savep; + uint32_t attrlen, + bitmap[2] = {0}; + struct kvec *iov = req->rq_rcv_buf.head; + int status; + + *acl_len = 0; + if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + goto out; + if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) + goto out; + if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) + goto out; + + if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { + int hdrlen, recvd; + + /* We ignore &savep and don't do consistency checks on + * the attr length. Let userspace figure it out.... */ + hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; + recvd = req->rq_rcv_buf.len - hdrlen; + if (attrlen > recvd) { + printk(KERN_WARNING "NFS: server cheating in getattr" + " acl reply: attrlen %u > recvd %u\n", + attrlen, recvd); + return -EINVAL; + } + if (attrlen <= *acl_len) + xdr_read_pages(xdr, attrlen); + *acl_len = attrlen; + } + +out: + return status; +} + static int decode_savefh(struct xdr_stream *xdr) { @@ -3418,6 +3494,29 @@ out: /* + * Decode GETACL response + */ +static int +nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status) + goto out; + status = decode_putfh(&xdr); + if (status) + goto out; + status = decode_getacl(&xdr, rqstp, acl_len); + +out: + return status; +} + +/* * Decode CLOSE response */ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res) @@ -4017,6 +4116,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(READDIR, enc_readdir, dec_readdir), PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), + PROC(GETACL, enc_getacl, dec_getacl), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 5ca8a8d..6ee7e25 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -382,6 +382,7 @@ enum { NFSPROC4_CLNT_READDIR, NFSPROC4_CLNT_SERVER_CAPS, NFSPROC4_CLNT_DELEGRETURN, + NFSPROC4_CLNT_GETACL, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index cf38db5..9f5e1d4 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -326,6 +326,13 @@ struct nfs_setattrargs { const u32 * bitmask; }; +struct nfs_getaclargs { + struct nfs_fh * fh; + size_t acl_len; + unsigned int acl_pgbase; + struct page ** acl_pages; +}; + struct nfs_setattrres { struct nfs_fattr * fattr; const struct nfs_server * server; -- cgit v0.10.2 From aa1870af92d8f6d6db0883696516a83ff2b695a6 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 22 Jun 2005 17:16:22 +0000 Subject: [PATCH] NFSv4: ACL support for the NFSv4 client: read Client-side support for NFSv4 ACLs. Exports the raw xdr code via the system.nfs4_acl extended attribute. It is up to userspace to decode the acl (and to provide correctly xdr'd acls on setxattr), and to convert to/from POSIX ACLs if desired. This patch provides only the read support. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1b14d17..c91c099 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2162,6 +2162,60 @@ nfs4_proc_file_release(struct inode *inode, struct file *filp) return 0; } +static inline int nfs4_server_supports_acls(struct nfs_server *server) +{ + return (server->caps & NFS_CAP_ACLS) + && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL) + && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL); +} + +/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that + * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on + * the stack. + */ +#define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) + +static void buf_to_pages(const void *buf, size_t buflen, + struct page **pages, unsigned int *pgbase) +{ + const void *p = buf; + + *pgbase = offset_in_page(buf); + p -= *pgbase; + while (p < buf + buflen) { + *(pages++) = virt_to_page(p); + p += PAGE_CACHE_SIZE; + } +} + +static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) +{ + struct nfs_server *server = NFS_SERVER(inode); + struct page *pages[NFS4ACL_MAXPAGES]; + struct nfs_getaclargs args = { + .fh = NFS_FH(inode), + .acl_pages = pages, + .acl_len = buflen, + }; + size_t resp_len = buflen; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], + .rpc_argp = &args, + .rpc_resp = &resp_len, + }; + int ret; + + if (!nfs4_server_supports_acls(server)) + return -EOPNOTSUPP; + buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); + ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + if (buflen && resp_len > buflen) + return -ERANGE; + if (ret == 0) + ret = resp_len; + return ret; +} + static int nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) { @@ -2733,6 +2787,8 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) } +#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" + int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, size_t buflen, int flags) { @@ -2746,18 +2802,23 @@ int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf, size_t buflen) { - return -EOPNOTSUPP; + struct inode *inode = dentry->d_inode; + + if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) + return -EOPNOTSUPP; + + return nfs4_proc_get_acl(inode, buf, buflen); } ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) { - ssize_t len = 0; + size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1; if (buf && buflen < len) return -ERANGE; if (buf) - memcpy(buf, "", 0); - return 0; + memcpy(buf, XATTR_NAME_NFSV4_ACL, len); + return len; } struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { -- cgit v0.10.2 From 23ec6965c20db96bc8ea7af0ec178f074dd31c40 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 22 Jun 2005 17:16:22 +0000 Subject: [PATCH] NFSv4: Client-side xdr for writing NFSv4 acls Client-side support for NFSv4 acls: xdr encoding and decoding routines for writing acls Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 6f1c003..325cd6d 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -372,6 +372,13 @@ static int nfs_stat_to_errno(int); decode_putfh_maxsz + \ op_decode_hdr_maxsz + \ nfs4_fattr_bitmap_maxsz + 1) +#define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + op_encode_hdr_maxsz + 4 + \ + nfs4_fattr_bitmap_maxsz + 1) +#define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) static struct { unsigned int mode; @@ -471,7 +478,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s * In the worst-case, this would be * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) * = 36 bytes, plus any contribution from variable-length fields - * such as owner/group/acl's. + * such as owner/group. */ len = 16; @@ -1096,6 +1103,25 @@ static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client } static int +encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg) +{ + uint32_t *p; + + RESERVE_SPACE(4+sizeof(zero_stateid.data)); + WRITE32(OP_SETATTR); + WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data)); + RESERVE_SPACE(2*4); + WRITE32(1); + WRITE32(FATTR4_WORD0_ACL); + if (arg->acl_len % 4) + return -EINVAL; + RESERVE_SPACE(4); + WRITE32(arg->acl_len); + xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); + return 0; +} + +static int encode_savefh(struct xdr_stream *xdr) { uint32_t *p; @@ -3492,6 +3518,48 @@ out: } +/* + * Encode an SETACL request + */ +static int +nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if (status) + goto out; + status = encode_setacl(&xdr, args); +out: + return status; +} +/* + * Decode SETACL response + */ +static int +nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status) + goto out; + status = decode_putfh(&xdr); + if (status) + goto out; + status = decode_setattr(&xdr, res); +out: + return status; +} /* * Decode GETACL response @@ -4117,6 +4185,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), PROC(GETACL, enc_getacl, dec_getacl), + PROC(SETACL, enc_setacl, dec_setacl), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 6ee7e25..5bb5b2f 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -383,6 +383,7 @@ enum { NFSPROC4_CLNT_SERVER_CAPS, NFSPROC4_CLNT_DELEGRETURN, NFSPROC4_CLNT_GETACL, + NFSPROC4_CLNT_SETACL, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 9f5e1d4..46b206b 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -326,6 +326,13 @@ struct nfs_setattrargs { const u32 * bitmask; }; +struct nfs_setaclargs { + struct nfs_fh * fh; + size_t acl_len; + unsigned int acl_pgbase; + struct page ** acl_pages; +}; + struct nfs_getaclargs { struct nfs_fh * fh; size_t acl_len; -- cgit v0.10.2 From 4b580ee3dc00f9828a9a7aad2724f448fdc94075 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 22 Jun 2005 17:16:23 +0000 Subject: [PATCH] NFSv4: ACL support for the NFSv4 client: write Client-side write support for NFSv4 ACLs. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c91c099..d969dd1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2216,6 +2216,29 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) return ret; } +static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) +{ + struct nfs_server *server = NFS_SERVER(inode); + struct page *pages[NFS4ACL_MAXPAGES]; + struct nfs_setaclargs arg = { + .fh = NFS_FH(inode), + .acl_pages = pages, + .acl_len = buflen, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], + .rpc_argp = &arg, + .rpc_resp = NULL, + }; + int ret; + + if (!nfs4_server_supports_acls(server)) + return -EOPNOTSUPP; + buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); + ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); + return ret; +} + static int nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) { @@ -2792,7 +2815,16 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, size_t buflen, int flags) { - return -EOPNOTSUPP; + struct inode *inode = dentry->d_inode; + + if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) + return -EOPNOTSUPP; + + if (!S_ISREG(inode->i_mode) && + (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) + return -EPERM; + + return nfs4_proc_set_acl(inode, buf, buflen); } /* The getxattr man page suggests returning -ENODATA for unknown attributes, -- cgit v0.10.2 From e50a1c2e1f816c81eed6a589019052cb44189267 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 22 Jun 2005 17:16:23 +0000 Subject: [PATCH] NFSv4: client-side caching NFSv4 ACLs Add nfs4_acl field to the nfs_inode, and use it to cache acls. Only cache acls of size up to a page. Also prepare for up to a page of acl data even when the user doesn't pass in a buffer, as when they want to get the acl length to decide what size buffer to allocate. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index c45bd52..350c48c 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -142,10 +142,6 @@ nfs_delete_inode(struct inode * inode) clear_inode(inode); } -/* - * For the moment, the only task for the NFS clear_inode method is to - * release the mmap credential - */ static void nfs_clear_inode(struct inode *inode) { @@ -1923,6 +1919,9 @@ static struct inode *nfs_alloc_inode(struct super_block *sb) if (!nfsi) return NULL; nfsi->flags = 0; +#ifdef CONFIG_NFS_V4 + nfsi->nfs4_acl = NULL; +#endif /* CONFIG_NFS_V4 */ return &nfsi->vfs_inode; } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d969dd1..128d01c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2188,9 +2188,75 @@ static void buf_to_pages(const void *buf, size_t buflen, } } -static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) +struct nfs4_cached_acl { + int cached; + size_t len; + char data[]; +}; + +static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + spin_lock(&inode->i_lock); + kfree(nfsi->nfs4_acl); + nfsi->nfs4_acl = acl; + spin_unlock(&inode->i_lock); +} + +static void nfs4_zap_acl_attr(struct inode *inode) +{ + nfs4_set_cached_acl(inode, NULL); +} + +static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen) +{ + struct nfs_inode *nfsi = NFS_I(inode); + struct nfs4_cached_acl *acl; + int ret = -ENOENT; + + spin_lock(&inode->i_lock); + acl = nfsi->nfs4_acl; + if (acl == NULL) + goto out; + if (buf == NULL) /* user is just asking for length */ + goto out_len; + if (acl->cached == 0) + goto out; + ret = -ERANGE; /* see getxattr(2) man page */ + if (acl->len > buflen) + goto out; + memcpy(buf, acl->data, acl->len); +out_len: + ret = acl->len; +out: + spin_unlock(&inode->i_lock); + return ret; +} + +static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len) +{ + struct nfs4_cached_acl *acl; + + if (buf && acl_len <= PAGE_SIZE) { + acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); + if (acl == NULL) + goto out; + acl->cached = 1; + memcpy(acl->data, buf, acl_len); + } else { + acl = kmalloc(sizeof(*acl), GFP_KERNEL); + if (acl == NULL) + goto out; + acl->cached = 0; + } + acl->len = acl_len; +out: + nfs4_set_cached_acl(inode, acl); +} + +static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) { - struct nfs_server *server = NFS_SERVER(inode); struct page *pages[NFS4ACL_MAXPAGES]; struct nfs_getaclargs args = { .fh = NFS_FH(inode), @@ -2198,24 +2264,66 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) .acl_len = buflen, }; size_t resp_len = buflen; + void *resp_buf; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], .rpc_argp = &args, .rpc_resp = &resp_len, }; + struct page *localpage = NULL; int ret; - if (!nfs4_server_supports_acls(server)) - return -EOPNOTSUPP; - buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); + if (buflen < PAGE_SIZE) { + /* As long as we're doing a round trip to the server anyway, + * let's be prepared for a page of acl data. */ + localpage = alloc_page(GFP_KERNEL); + resp_buf = page_address(localpage); + if (localpage == NULL) + return -ENOMEM; + args.acl_pages[0] = localpage; + args.acl_pgbase = 0; + args.acl_len = PAGE_SIZE; + } else { + resp_buf = buf; + buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); + } ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); - if (buflen && resp_len > buflen) - return -ERANGE; - if (ret == 0) - ret = resp_len; + if (ret) + goto out_free; + if (resp_len > args.acl_len) + nfs4_write_cached_acl(inode, NULL, resp_len); + else + nfs4_write_cached_acl(inode, resp_buf, resp_len); + if (buf) { + ret = -ERANGE; + if (resp_len > buflen) + goto out_free; + if (localpage) + memcpy(buf, resp_buf, resp_len); + } + ret = resp_len; +out_free: + if (localpage) + __free_page(localpage); return ret; } +static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) +{ + struct nfs_server *server = NFS_SERVER(inode); + int ret; + + if (!nfs4_server_supports_acls(server)) + return -EOPNOTSUPP; + ret = nfs_revalidate_inode(server, inode); + if (ret < 0) + return ret; + ret = nfs4_read_cached_acl(inode, buf, buflen); + if (ret != -ENOENT) + return ret; + return nfs4_get_acl_uncached(inode, buf, buflen); +} + static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) { struct nfs_server *server = NFS_SERVER(inode); @@ -2236,6 +2344,8 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen return -EOPNOTSUPP; buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); + if (ret == 0) + nfs4_write_cached_acl(inode, buf, buflen); return ret; } @@ -2907,6 +3017,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { .file_open = nfs4_proc_file_open, .file_release = nfs4_proc_file_release, .lock = nfs4_proc_lock, + .clear_acl_cache = nfs4_zap_acl_attr, }; /* diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 140bdf4..d2b5d7e 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -169,13 +169,13 @@ struct nfs_inode { wait_queue_head_t nfs_i_wait; #ifdef CONFIG_NFS_V4 + struct nfs4_cached_acl *nfs4_acl; /* NFSv4 state */ struct list_head open_states; struct nfs_delegation *delegation; int delegation_state; struct rw_semaphore rwsem; #endif /* CONFIG_NFS_V4*/ - struct inode vfs_inode; }; -- cgit v0.10.2 From 438b6fdebf2a2e8573e7290bc176feb4d4475f43 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 22 Jun 2005 17:16:23 +0000 Subject: [PATCH] RPC: Don't fall back from krb5p to krb5i We shouldn't be silently falling back from krb5p to krb5i. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index a33b627..7d88db8 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -675,9 +675,8 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) goto err_free; } gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); - /* FIXME: Will go away once privacy support is merged in */ - if (gss_auth->service == RPC_GSS_SVC_PRIVACY) - gss_auth->service = RPC_GSS_SVC_INTEGRITY; + if (gss_auth->service == 0) + goto err_put_mech; INIT_LIST_HEAD(&gss_auth->upcalls); spin_lock_init(&gss_auth->lock); auth = &gss_auth->rpc_auth; -- cgit v0.10.2 From 6a19275ada9137435da58990c8f8d3f58e170bf1 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 22 Jun 2005 17:16:23 +0000 Subject: [PATCH] RPC: [PATCH] improve rpcauthauth_create error returns Currently we return -ENOMEM for every single failure to create a new auth. This is actually accurate for auth_null and auth_unix, but for auth_gss it's a bit confusing. Allow rpcauth_create (and the ->create methods) to return errors. With this patch, the user may sometimes see an EINVAL instead. Whee. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 350c48c..97b3fe7 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -160,11 +160,10 @@ nfs_clear_inode(struct inode *inode) void nfs_umount_begin(struct super_block *sb) { - struct nfs_server *server = NFS_SB(sb); - struct rpc_clnt *rpc; + struct rpc_clnt *rpc = NFS_SB(sb)->client; /* -EIO all pending I/O */ - if ((rpc = server->client) != NULL) + if (!IS_ERR(rpc)) rpc_killall_tasks(rpc); } @@ -450,11 +449,14 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) return PTR_ERR(server->client); /* RFC 2623, sec 2.3.2 */ if (authflavor != RPC_AUTH_UNIX) { + struct rpc_auth *auth; + server->client_sys = rpc_clone_client(server->client); if (IS_ERR(server->client_sys)) return PTR_ERR(server->client_sys); - if (!rpcauth_create(RPC_AUTH_UNIX, server->client_sys)) - return -ENOMEM; + auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys); + if (IS_ERR(auth)) + return PTR_ERR(auth); } else { atomic_inc(&server->client->cl_count); server->client_sys = server->client; @@ -1450,6 +1452,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, memset(server, 0, sizeof(struct nfs_server)); /* Zero out the NFS state stuff */ init_nfsv4_state(server); + server->client = server->client_sys = ERR_PTR(-EINVAL); root = &server->fh; if (data->flags & NFS_MOUNT_VER3) @@ -1506,9 +1509,9 @@ static void nfs_kill_super(struct super_block *s) kill_anon_super(s); - if (server->client != NULL && !IS_ERR(server->client)) + if (!IS_ERR(server->client)) rpc_shutdown_client(server->client); - if (server->client_sys != NULL && !IS_ERR(server->client_sys)) + if (!IS_ERR(server->client_sys)) rpc_shutdown_client(server->client_sys); if (!(server->flags & NFS_MOUNT_NONLM)) @@ -1650,7 +1653,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, } down_write(&clp->cl_sem); - if (clp->cl_rpcclient == NULL) { + if (IS_ERR(clp->cl_rpcclient)) { xprt = xprt_create_proto(proto, &server->addr, &timeparms); if (IS_ERR(xprt)) { up_write(&clp->cl_sem); @@ -1711,9 +1714,12 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, } if (clnt->cl_auth->au_flavor != authflavour) { - if (rpcauth_create(authflavour, clnt) == NULL) { + struct rpc_auth *auth; + + auth = rpcauth_create(authflavour, clnt); + if (IS_ERR(auth)) { dprintk("%s: couldn't create credcache!\n", __FUNCTION__); - return -ENOMEM; + return PTR_ERR(auth); } } @@ -1788,6 +1794,7 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, memset(server, 0, sizeof(struct nfs_server)); /* Zero out the NFS state stuff */ init_nfsv4_state(server); + server->client = server->client_sys = ERR_PTR(-EINVAL); p = nfs_copy_user_string(NULL, &data->hostname, 256); if (IS_ERR(p)) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 17b187f..591ad1d 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -110,6 +110,7 @@ nfs4_alloc_client(struct in_addr *addr) INIT_LIST_HEAD(&clp->cl_superblocks); init_waitqueue_head(&clp->cl_waitq); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); + clp->cl_rpcclient = ERR_PTR(-EINVAL); clp->cl_boot_time = CURRENT_TIME; clp->cl_state = 1 << NFS4CLNT_OK; return clp; @@ -131,7 +132,7 @@ nfs4_free_client(struct nfs4_client *clp) if (clp->cl_cred) put_rpccred(clp->cl_cred); nfs_idmap_delete(clp); - if (clp->cl_rpcclient) + if (!IS_ERR(clp->cl_rpcclient)) rpc_shutdown_client(clp->cl_rpcclient); kfree(clp); nfs_callback_down(); diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 9bcec9b..505e2d4 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -66,10 +66,10 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) u32 flavor = pseudoflavor_to_flavor(pseudoflavor); if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor])) - return NULL; + return ERR_PTR(-EINVAL); auth = ops->create(clnt, pseudoflavor); - if (!auth) - return NULL; + if (IS_ERR(auth)) + return auth; if (clnt->cl_auth) rpcauth_destroy(clnt->cl_auth); clnt->cl_auth = auth; diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 7d88db8..2f7b867 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -660,14 +660,16 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) { struct gss_auth *gss_auth; struct rpc_auth * auth; + int err = -ENOMEM; /* XXX? */ dprintk("RPC: creating GSS authenticator for client %p\n",clnt); if (!try_module_get(THIS_MODULE)) - return NULL; + return ERR_PTR(err); if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) goto out_dec; gss_auth->client = clnt; + err = -EINVAL; gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); if (!gss_auth->mech) { printk(KERN_WARNING "%s: Pseudoflavor %d not found!", @@ -686,15 +688,18 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) auth->au_flavor = flavor; atomic_set(&auth->au_count, 1); - if (rpcauth_init_credcache(auth, GSS_CRED_EXPIRE) < 0) + err = rpcauth_init_credcache(auth, GSS_CRED_EXPIRE); + if (err) goto err_put_mech; snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", clnt->cl_pathname, gss_auth->mech->gm_name); gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); - if (IS_ERR(gss_auth->dentry)) + if (IS_ERR(gss_auth->dentry)) { + err = PTR_ERR(gss_auth->dentry); goto err_put_mech; + } return auth; err_put_mech: @@ -703,7 +708,7 @@ err_free: kfree(gss_auth); out_dec: module_put(THIS_MODULE); - return NULL; + return ERR_PTR(err); } static void diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index b36797a..9da1deb 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -103,6 +103,7 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname, { struct rpc_version *version; struct rpc_clnt *clnt = NULL; + struct rpc_auth *auth; int err; int len; @@ -157,10 +158,11 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname, if (err < 0) goto out_no_path; - err = -ENOMEM; - if (!rpcauth_create(flavor, clnt)) { + auth = rpcauth_create(flavor, clnt); + if (IS_ERR(auth)) { printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n", flavor); + err = PTR_ERR(auth); goto out_no_auth; } -- cgit v0.10.2 From cdf477068e6db0c3e19df96f46abb85202de138c Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 22 Jun 2005 17:16:23 +0000 Subject: [PATCH] RPC: Return -EPFNOSUPPORT for RPC programs that are unavailable Signed-off-by: Andreas Gruenbacher Signed-off-by: Olaf Kirch Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 9da1deb..33f12b8 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1021,10 +1021,11 @@ call_verify(struct rpc_task *task) case RPC_AUTH_ERROR: break; case RPC_MISMATCH: - printk(KERN_WARNING "%s: RPC call version mismatch!\n", __FUNCTION__); - goto out_eio; + dprintk("%s: RPC call version mismatch!\n", __FUNCTION__); + error = -EPROTONOSUPPORT; + goto out_err; default: - printk(KERN_WARNING "%s: RPC call rejected, unknown error: %x\n", __FUNCTION__, n); + dprintk("%s: RPC call rejected, unknown error: %x\n", __FUNCTION__, n); goto out_eio; } if (--len < 0) @@ -1075,23 +1076,26 @@ call_verify(struct rpc_task *task) case RPC_SUCCESS: return p; case RPC_PROG_UNAVAIL: - printk(KERN_WARNING "RPC: call_verify: program %u is unsupported by server %s\n", + dprintk("RPC: call_verify: program %u is unsupported by server %s\n", (unsigned int)task->tk_client->cl_prog, task->tk_client->cl_server); - goto out_eio; + error = -EPFNOSUPPORT; + goto out_err; case RPC_PROG_MISMATCH: - printk(KERN_WARNING "RPC: call_verify: program %u, version %u unsupported by server %s\n", + dprintk("RPC: call_verify: program %u, version %u unsupported by server %s\n", (unsigned int)task->tk_client->cl_prog, (unsigned int)task->tk_client->cl_vers, task->tk_client->cl_server); - goto out_eio; + error = -EPROTONOSUPPORT; + goto out_err; case RPC_PROC_UNAVAIL: - printk(KERN_WARNING "RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n", + dprintk("RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n", task->tk_msg.rpc_proc, task->tk_client->cl_prog, task->tk_client->cl_vers, task->tk_client->cl_server); - goto out_eio; + error = -EOPNOTSUPP; + goto out_err; case RPC_GARBAGE_ARGS: dprintk("RPC: %4d %s: server saw garbage\n", task->tk_pid, __FUNCTION__); break; /* retry */ @@ -1104,7 +1108,7 @@ out_retry: task->tk_client->cl_stats->rpcgarbage++; if (task->tk_garb_retry) { task->tk_garb_retry--; - dprintk(KERN_WARNING "RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid); + dprintk("RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid); task->tk_action = call_bind; return NULL; } -- cgit v0.10.2 From 007e251f2b2760f738c92adc8c80cbae0bed3ce5 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 22 Jun 2005 17:16:23 +0000 Subject: [PATCH] RPC: Allow multiple RPC client programs to share the same transport Signed-off-by: Andreas Gruenbacher Acked-by: Olaf Kirch Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index d25e80f..ab151bb 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -114,6 +114,8 @@ struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, struct rpc_clnt *rpc_new_client(struct rpc_xprt *xprt, char *servname, struct rpc_program *info, u32 version, rpc_authflavor_t authflavor); +struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, + struct rpc_program *, int); struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); int rpc_shutdown_client(struct rpc_clnt *); int rpc_destroy_client(struct rpc_clnt *); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 33f12b8..c979fcf 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -241,6 +241,8 @@ rpc_clone_client(struct rpc_clnt *clnt) rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); if (new->cl_auth) atomic_inc(&new->cl_auth->au_count); + new->cl_pmap = &new->cl_pmap_default; + rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait"); return new; out_no_clnt: printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); @@ -329,6 +331,44 @@ rpc_release_client(struct rpc_clnt *clnt) rpc_destroy_client(clnt); } +/** + * rpc_bind_new_program - bind a new RPC program to an existing client + * @old - old rpc_client + * @program - rpc program to set + * @vers - rpc program version + * + * Clones the rpc client and sets up a new RPC program. This is mainly + * of use for enabling different RPC programs to share the same transport. + * The Sun NFSv2/v3 ACL protocol can do this. + */ +struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, + struct rpc_program *program, + int vers) +{ + struct rpc_clnt *clnt; + struct rpc_version *version; + int err; + + BUG_ON(vers >= program->nrvers || !program->version[vers]); + version = program->version[vers]; + clnt = rpc_clone_client(old); + if (IS_ERR(clnt)) + goto out; + clnt->cl_procinfo = version->procs; + clnt->cl_maxproc = version->nrprocs; + clnt->cl_protname = program->name; + clnt->cl_prog = program->number; + clnt->cl_vers = version->number; + clnt->cl_stats = program->stats; + err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR); + if (err != 0) { + rpc_shutdown_client(clnt); + clnt = ERR_PTR(err); + } +out: + return clnt; +} + /* * Default callback for async RPC calls */ diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index df4d84c..4e81f27 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -53,6 +53,9 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt) task->tk_pid, clnt->cl_server, map->pm_prog, map->pm_vers, map->pm_prot); + /* Autobind on cloned rpc clients is discouraged */ + BUG_ON(clnt->cl_parent != clnt); + spin_lock(&pmap_lock); if (map->pm_binding) { rpc_sleep_on(&map->pm_bindwait, task, NULL, NULL); diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 1b0ff7e..d8673f6 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -42,6 +42,7 @@ EXPORT_SYMBOL(rpc_release_task); /* RPC client functions */ EXPORT_SYMBOL(rpc_create_client); EXPORT_SYMBOL(rpc_clone_client); +EXPORT_SYMBOL(rpc_bind_new_program); EXPORT_SYMBOL(rpc_destroy_client); EXPORT_SYMBOL(rpc_shutdown_client); EXPORT_SYMBOL(rpc_release_client); -- cgit v0.10.2 From e053d1ab62c8ef0eff3dd4c95448cad3c6d2fbf4 Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Wed, 22 Jun 2005 17:16:24 +0000 Subject: [PATCH] RPC: Lazy RPC receive buffer allocation Signed-off-by: Olaf Kirch Signed-off-by: Andreas Gruenbacher Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 541dcf8..0f5b7a5 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -160,7 +160,7 @@ typedef struct { typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); -extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, +extern int xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, skb_reader_t *, skb_read_actor_t); struct socket; diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index f86d1ba..65b268d 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -176,7 +176,7 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, xdr->buflen += len; } -void +int xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, skb_reader_t *desc, skb_read_actor_t copy_actor) @@ -190,7 +190,7 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, len -= base; ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); if (ret != len || !desc->count) - return; + return 0; base = 0; } else base -= len; @@ -210,6 +210,14 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, do { char *kaddr; + /* ACL likes to be lazy in allocating pages - ACLs + * are small by default but can get huge. */ + if (unlikely(*ppage == NULL)) { + *ppage = alloc_page(GFP_ATOMIC); + if (unlikely(*ppage == NULL)) + return -ENOMEM; + } + len = PAGE_CACHE_SIZE; kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA); if (base) { @@ -226,13 +234,15 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, flush_dcache_page(*ppage); kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); if (ret != len || !desc->count) - return; + return 0; ppage++; } while ((pglen -= len) != 0); copy_tail: len = xdr->tail[0].iov_len; if (base < len) copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); + + return 0; } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index c74a6bb..a180ed4 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -725,7 +725,8 @@ csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) goto no_checksum; desc.csum = csum_partial(skb->data, desc.offset, skb->csum); - xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits); + if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits) < 0) + return -1; if (desc.offset != skb->len) { unsigned int csum2; csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0); @@ -737,7 +738,8 @@ csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) return -1; return 0; no_checksum: - xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits); + if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0) + return -1; if (desc.count) return -1; return 0; @@ -907,6 +909,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) struct rpc_rqst *req; struct xdr_buf *rcvbuf; size_t len; + int r; /* Find and lock the request corresponding to this xid */ spin_lock(&xprt->sock_lock); @@ -927,16 +930,30 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) len = xprt->tcp_reclen - xprt->tcp_offset; memcpy(&my_desc, desc, sizeof(my_desc)); my_desc.count = len; - xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, + r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, &my_desc, tcp_copy_data); desc->count -= len; desc->offset += len; } else - xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, + r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, desc, tcp_copy_data); xprt->tcp_copied += len; xprt->tcp_offset += len; + if (r < 0) { + /* Error when copying to the receive buffer, + * usually because we weren't able to allocate + * additional buffer pages. All we can do now + * is turn off XPRT_COPY_DATA, so the request + * will not receive any additional updates, + * and time out. + * Any remaining data from this record will + * be discarded. + */ + xprt->tcp_flags &= ~XPRT_COPY_DATA; + goto out; + } + if (xprt->tcp_copied == req->rq_private_buf.buflen) xprt->tcp_flags &= ~XPRT_COPY_DATA; else if (xprt->tcp_offset == xprt->tcp_reclen) { @@ -949,6 +966,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) req->rq_task->tk_pid); xprt_complete_rqst(xprt, req, xprt->tcp_copied); } +out: spin_unlock(&xprt->sock_lock); tcp_check_recm(xprt); } -- cgit v0.10.2 From 7e06b53d796a3740307b54aa2799077f8a0c84e7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:24 +0000 Subject: [PATCH] RPC: fix accounting bug in the case of a truncated RPC message Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 0f5b7a5..5d1eed2 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -160,7 +160,7 @@ typedef struct { typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); -extern int xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, +extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, skb_reader_t *, skb_read_actor_t); struct socket; diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 65b268d..b3ac3f7 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -176,21 +176,23 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, xdr->buflen += len; } -int +ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, skb_reader_t *desc, skb_read_actor_t copy_actor) { struct page **ppage = xdr->pages; unsigned int len, pglen = xdr->page_len; + ssize_t copied = 0; int ret; len = xdr->head[0].iov_len; if (base < len) { len -= base; ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); + copied += ret; if (ret != len || !desc->count) - return 0; + goto out; base = 0; } else base -= len; @@ -214,8 +216,11 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, * are small by default but can get huge. */ if (unlikely(*ppage == NULL)) { *ppage = alloc_page(GFP_ATOMIC); - if (unlikely(*ppage == NULL)) - return -ENOMEM; + if (unlikely(*ppage == NULL)) { + if (copied == 0) + copied = -ENOMEM; + goto out; + } } len = PAGE_CACHE_SIZE; @@ -233,16 +238,17 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, } flush_dcache_page(*ppage); kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); + copied += ret; if (ret != len || !desc->count) - return 0; + goto out; ppage++; } while ((pglen -= len) != 0); copy_tail: len = xdr->tail[0].iov_len; if (base < len) - copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); - - return 0; + copied += copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); +out: + return copied; } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index a180ed4..ef941e7 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -823,10 +823,15 @@ tcp_copy_data(skb_reader_t *desc, void *p, size_t len) { if (len > desc->count) len = desc->count; - if (skb_copy_bits(desc->skb, desc->offset, p, len)) + if (skb_copy_bits(desc->skb, desc->offset, p, len)) { + dprintk("RPC: failed to copy %zu bytes from skb. %zu bytes remain\n", + len, desc->count); return 0; + } desc->offset += len; desc->count -= len; + dprintk("RPC: copied %zu bytes from skb. %zu bytes remain\n", + len, desc->count); return len; } @@ -865,6 +870,8 @@ tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) static void tcp_check_recm(struct rpc_xprt *xprt) { + dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u, tcp_flags = %lx\n", + xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_flags); if (xprt->tcp_offset == xprt->tcp_reclen) { xprt->tcp_flags |= XPRT_COPY_RECM; xprt->tcp_offset = 0; @@ -909,7 +916,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) struct rpc_rqst *req; struct xdr_buf *rcvbuf; size_t len; - int r; + ssize_t r; /* Find and lock the request corresponding to this xid */ spin_lock(&xprt->sock_lock); @@ -932,15 +939,17 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) my_desc.count = len; r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, &my_desc, tcp_copy_data); - desc->count -= len; - desc->offset += len; + desc->count -= r; + desc->offset += r; } else r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, desc, tcp_copy_data); - xprt->tcp_copied += len; - xprt->tcp_offset += len; - if (r < 0) { + if (r > 0) { + xprt->tcp_copied += r; + xprt->tcp_offset += r; + } + if (r != len) { /* Error when copying to the receive buffer, * usually because we weren't able to allocate * additional buffer pages. All we can do now @@ -951,9 +960,18 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) * be discarded. */ xprt->tcp_flags &= ~XPRT_COPY_DATA; + dprintk("RPC: XID %08x truncated request\n", + ntohl(xprt->tcp_xid)); + dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", + xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); goto out; } + dprintk("RPC: XID %08x read %u bytes\n", + ntohl(xprt->tcp_xid), r); + dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", + xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); + if (xprt->tcp_copied == req->rq_private_buf.buflen) xprt->tcp_flags &= ~XPRT_COPY_DATA; else if (xprt->tcp_offset == xprt->tcp_reclen) { @@ -961,12 +979,12 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) xprt->tcp_flags &= ~XPRT_COPY_DATA; } +out: if (!(xprt->tcp_flags & XPRT_COPY_DATA)) { dprintk("RPC: %4d received reply complete\n", req->rq_task->tk_pid); xprt_complete_rqst(xprt, req, xprt->tcp_copied); } -out: spin_unlock(&xprt->sock_lock); tcp_check_recm(xprt); } @@ -985,6 +1003,7 @@ tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) desc->count -= len; desc->offset += len; xprt->tcp_offset += len; + dprintk("RPC: discarded %u bytes\n", len); tcp_check_recm(xprt); } -- cgit v0.10.2 From bd8100e7eda87507649c6ba4cb32173b34e49986 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 22 Jun 2005 17:16:24 +0000 Subject: [PATCH] RPC: Encode and decode arbitrary XDR arrays Signed-off-by: Andreas Gruenbacher Acked-by: Olaf Kirch Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 5d1eed2..34ec3e8 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -146,7 +146,8 @@ extern void xdr_shift_buf(struct xdr_buf *, size_t); extern void xdr_buf_from_iov(struct kvec *, struct xdr_buf *); extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, int, int); extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, int); -extern int read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len); +extern int read_bytes_from_xdr_buf(struct xdr_buf *, int, void *, int); +extern int write_bytes_to_xdr_buf(struct xdr_buf *, int, void *, int); /* * Helper structure for copying from an sk_buff. @@ -168,6 +169,22 @@ struct sockaddr; extern int xdr_sendpages(struct socket *, struct sockaddr *, int, struct xdr_buf *, unsigned int, int); +extern int xdr_encode_word(struct xdr_buf *, int, u32); +extern int xdr_decode_word(struct xdr_buf *, int, u32 *); + +struct xdr_array2_desc; +typedef int (*xdr_xcode_elem_t)(struct xdr_array2_desc *desc, void *elem); +struct xdr_array2_desc { + unsigned int elem_size; + unsigned int array_len; + xdr_xcode_elem_t xcode; +}; + +extern int xdr_decode_array2(struct xdr_buf *buf, unsigned int base, + struct xdr_array2_desc *desc); +extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base, + struct xdr_array2_desc *desc); + /* * Provide some simple tools for XDR buffer overflow-checking etc. */ diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index d8673f6..32e8acb 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -129,6 +129,10 @@ EXPORT_SYMBOL(xdr_encode_netobj); EXPORT_SYMBOL(xdr_encode_pages); EXPORT_SYMBOL(xdr_inline_pages); EXPORT_SYMBOL(xdr_shift_buf); +EXPORT_SYMBOL(xdr_encode_word); +EXPORT_SYMBOL(xdr_decode_word); +EXPORT_SYMBOL(xdr_encode_array2); +EXPORT_SYMBOL(xdr_decode_array2); EXPORT_SYMBOL(xdr_buf_from_iov); EXPORT_SYMBOL(xdr_buf_subsegment); EXPORT_SYMBOL(xdr_buf_read_netobj); diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index b3ac3f7..8a4d9c1 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -887,8 +887,34 @@ out: return status; } -static int -read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) +/* obj is assumed to point to allocated memory of size at least len: */ +int +write_bytes_to_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len) +{ + struct xdr_buf subbuf; + int this_len; + int status; + + status = xdr_buf_subsegment(buf, &subbuf, base, len); + if (status) + goto out; + this_len = min(len, (int)subbuf.head[0].iov_len); + memcpy(subbuf.head[0].iov_base, obj, this_len); + len -= this_len; + obj += this_len; + this_len = min(len, (int)subbuf.page_len); + if (this_len) + _copy_to_pages(subbuf.pages, subbuf.page_base, obj, this_len); + len -= this_len; + obj += this_len; + this_len = min(len, (int)subbuf.tail[0].iov_len); + memcpy(subbuf.tail[0].iov_base, obj, this_len); +out: + return status; +} + +int +xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj) { u32 raw; int status; @@ -900,6 +926,14 @@ read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) return 0; } +int +xdr_encode_word(struct xdr_buf *buf, int base, u32 obj) +{ + u32 raw = htonl(obj); + + return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj)); +} + /* If the netobj starting offset bytes from the start of xdr_buf is contained * entirely in the head or the tail, set object to point to it; otherwise * try to find space for it at the end of the tail, copy it there, and @@ -910,7 +944,7 @@ xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset) u32 tail_offset = buf->head[0].iov_len + buf->page_len; u32 obj_end_offset; - if (read_u32_from_xdr_buf(buf, offset, &obj->len)) + if (xdr_decode_word(buf, offset, &obj->len)) goto out; obj_end_offset = offset + 4 + obj->len; @@ -943,3 +977,219 @@ xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset) out: return -1; } + +/* Returns 0 on success, or else a negative error code. */ +static int +xdr_xcode_array2(struct xdr_buf *buf, unsigned int base, + struct xdr_array2_desc *desc, int encode) +{ + char *elem = NULL, *c; + unsigned int copied = 0, todo, avail_here; + struct page **ppages = NULL; + int err; + + if (encode) { + if (xdr_encode_word(buf, base, desc->array_len) != 0) + return -EINVAL; + } else { + if (xdr_decode_word(buf, base, &desc->array_len) != 0 || + (unsigned long) base + 4 + desc->array_len * + desc->elem_size > buf->len) + return -EINVAL; + } + base += 4; + + if (!desc->xcode) + return 0; + + todo = desc->array_len * desc->elem_size; + + /* process head */ + if (todo && base < buf->head->iov_len) { + c = buf->head->iov_base + base; + avail_here = min_t(unsigned int, todo, + buf->head->iov_len - base); + todo -= avail_here; + + while (avail_here >= desc->elem_size) { + err = desc->xcode(desc, c); + if (err) + goto out; + c += desc->elem_size; + avail_here -= desc->elem_size; + } + if (avail_here) { + if (!elem) { + elem = kmalloc(desc->elem_size, GFP_KERNEL); + err = -ENOMEM; + if (!elem) + goto out; + } + if (encode) { + err = desc->xcode(desc, elem); + if (err) + goto out; + memcpy(c, elem, avail_here); + } else + memcpy(elem, c, avail_here); + copied = avail_here; + } + base = buf->head->iov_len; /* align to start of pages */ + } + + /* process pages array */ + base -= buf->head->iov_len; + if (todo && base < buf->page_len) { + unsigned int avail_page; + + avail_here = min(todo, buf->page_len - base); + todo -= avail_here; + + base += buf->page_base; + ppages = buf->pages + (base >> PAGE_CACHE_SHIFT); + base &= ~PAGE_CACHE_MASK; + avail_page = min_t(unsigned int, PAGE_CACHE_SIZE - base, + avail_here); + c = kmap(*ppages) + base; + + while (avail_here) { + avail_here -= avail_page; + if (copied || avail_page < desc->elem_size) { + unsigned int l = min(avail_page, + desc->elem_size - copied); + if (!elem) { + elem = kmalloc(desc->elem_size, + GFP_KERNEL); + err = -ENOMEM; + if (!elem) + goto out; + } + if (encode) { + if (!copied) { + err = desc->xcode(desc, elem); + if (err) + goto out; + } + memcpy(c, elem + copied, l); + copied += l; + if (copied == desc->elem_size) + copied = 0; + } else { + memcpy(elem + copied, c, l); + copied += l; + if (copied == desc->elem_size) { + err = desc->xcode(desc, elem); + if (err) + goto out; + copied = 0; + } + } + avail_page -= l; + c += l; + } + while (avail_page >= desc->elem_size) { + err = desc->xcode(desc, c); + if (err) + goto out; + c += desc->elem_size; + avail_page -= desc->elem_size; + } + if (avail_page) { + unsigned int l = min(avail_page, + desc->elem_size - copied); + if (!elem) { + elem = kmalloc(desc->elem_size, + GFP_KERNEL); + err = -ENOMEM; + if (!elem) + goto out; + } + if (encode) { + if (!copied) { + err = desc->xcode(desc, elem); + if (err) + goto out; + } + memcpy(c, elem + copied, l); + copied += l; + if (copied == desc->elem_size) + copied = 0; + } else { + memcpy(elem + copied, c, l); + copied += l; + if (copied == desc->elem_size) { + err = desc->xcode(desc, elem); + if (err) + goto out; + copied = 0; + } + } + } + if (avail_here) { + kunmap(*ppages); + ppages++; + c = kmap(*ppages); + } + + avail_page = min(avail_here, + (unsigned int) PAGE_CACHE_SIZE); + } + base = buf->page_len; /* align to start of tail */ + } + + /* process tail */ + base -= buf->page_len; + if (todo) { + c = buf->tail->iov_base + base; + if (copied) { + unsigned int l = desc->elem_size - copied; + + if (encode) + memcpy(c, elem + copied, l); + else { + memcpy(elem + copied, c, l); + err = desc->xcode(desc, elem); + if (err) + goto out; + } + todo -= l; + c += l; + } + while (todo) { + err = desc->xcode(desc, c); + if (err) + goto out; + c += desc->elem_size; + todo -= desc->elem_size; + } + } + err = 0; + +out: + if (elem) + kfree(elem); + if (ppages) + kunmap(*ppages); + return err; +} + +int +xdr_decode_array2(struct xdr_buf *buf, unsigned int base, + struct xdr_array2_desc *desc) +{ + if (base >= buf->len) + return -EINVAL; + + return xdr_xcode_array2(buf, base, desc, 0); +} + +int +xdr_encode_array2(struct xdr_buf *buf, unsigned int base, + struct xdr_array2_desc *desc) +{ + if ((unsigned long) base + 4 + desc->array_len * desc->elem_size > + buf->head->iov_len + buf->page_len + buf->tail->iov_len) + return -EINVAL; + + return xdr_xcode_array2(buf, base, desc, 1); +} -- cgit v0.10.2 From a838cc49d9a7d5652262a6d1b628628cadffa877 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 22 Jun 2005 17:16:24 +0000 Subject: [PATCH] NFSD: Add NFS3ERR_NOTSUPP to the nfsd error mapping table Add the missing NFS3ERR_NOTSUPP error code (defined in NFSv3) to the system-to-protocol-error table in nfsd. The nfsacl extension uses this error code. Signed-off-by: Andreas Gruenbacher Signed-off-by: Olaf Kirch Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 757f9d2..0aa1b96 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -591,6 +591,7 @@ nfserrno (int errno) { nfserr_dropit, -ENOMEM }, { nfserr_badname, -ESRCH }, { nfserr_io, -ETXTBSY }, + { nfserr_notsupp, -EOPNOTSUPP }, { -1, -EIO } }; int i; -- cgit v0.10.2 From 9ba02638e4be28dd4ff724202a640264427c62d1 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 22 Jun 2005 17:16:24 +0000 Subject: [PATCH] RPC: Allow the sunrpc server to multiplex serveral programs on a single port The NFS and NFSACL programs run on the same RPC transport. This patch adds support for this by converting svc_program into a chained list of programs (server-side). Signed-off-by: Andreas Gruenbacher Signed-off-by: Olaf Kirch Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 3700397..facb944 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -240,9 +240,10 @@ struct svc_deferred_req { }; /* - * RPC program + * List of RPC programs on the same transport endpoint */ struct svc_program { + struct svc_program * pg_next; /* other programs (same xprt) */ u32 pg_prog; /* program number */ unsigned int pg_lovers; /* lowest version */ unsigned int pg_hivers; /* lowest version */ diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index a02d424..e9bd912 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -35,20 +35,24 @@ svc_create(struct svc_program *prog, unsigned int bufsize) if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL))) return NULL; memset(serv, 0, sizeof(*serv)); + serv->sv_name = prog->pg_name; serv->sv_program = prog; serv->sv_nrthreads = 1; serv->sv_stats = prog->pg_stats; serv->sv_bufsz = bufsize? bufsize : 4096; - prog->pg_lovers = prog->pg_nvers-1; xdrsize = 0; - for (vers=0; verspg_nvers ; vers++) - if (prog->pg_vers[vers]) { - prog->pg_hivers = vers; - if (prog->pg_lovers > vers) - prog->pg_lovers = vers; - if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) - xdrsize = prog->pg_vers[vers]->vs_xdrsize; - } + while (prog) { + prog->pg_lovers = prog->pg_nvers-1; + for (vers=0; verspg_nvers ; vers++) + if (prog->pg_vers[vers]) { + prog->pg_hivers = vers; + if (prog->pg_lovers > vers) + prog->pg_lovers = vers; + if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) + xdrsize = prog->pg_vers[vers]->vs_xdrsize; + } + prog = prog->pg_next; + } serv->sv_xdrsize = xdrsize; INIT_LIST_HEAD(&serv->sv_threads); INIT_LIST_HEAD(&serv->sv_sockets); @@ -56,8 +60,6 @@ svc_create(struct svc_program *prog, unsigned int bufsize) INIT_LIST_HEAD(&serv->sv_permsocks); spin_lock_init(&serv->sv_lock); - serv->sv_name = prog->pg_name; - /* Remove any stale portmap registrations */ svc_register(serv, 0, 0); @@ -339,7 +341,10 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) goto sendit; } - if (prog != progp->pg_prog) + for (progp = serv->sv_program; progp; progp = progp->pg_next) + if (prog == progp->pg_prog) + break; + if (progp == NULL) goto err_bad_prog; if (vers >= progp->pg_nvers || @@ -452,11 +457,7 @@ err_bad_auth: goto sendit; err_bad_prog: -#ifdef RPC_PARANOIA - if (prog != 100227 || progp->pg_prog != 100003) - printk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog); - /* else it is just a Solaris client seeing if ACLs are supported */ -#endif + dprintk("svc: unknown program %d\n", prog); serv->sv_stats->rpcbadfmt++; svc_putu32(resv, rpc_prog_unavail); goto sendit; -- cgit v0.10.2 From a257cdd0e2179630d3201c32ba14d7fcb3c3a055 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 22 Jun 2005 17:16:26 +0000 Subject: [PATCH] NFSD: Add server support for NFSv3 ACLs. This adds functions for encoding and decoding POSIX ACLs for the NFSACL protocol extension, and the GETACL and SETACL RPCs. The implementation is compatible with NFSACL in Solaris. Signed-off-by: Andreas Gruenbacher Acked-by: Olaf Kirch Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust diff --git a/fs/Kconfig b/fs/Kconfig index 178e274..d44b04d 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1353,6 +1353,7 @@ config NFSD select LOCKD select SUNRPC select EXPORTFS + select NFS_ACL_SUPPORT if NFSD_V3_ACL || NFSD_V2_ACL help If you want your Linux box to act as an NFS *server*, so that other computers on your local network which support NFS can access certain @@ -1376,6 +1377,10 @@ config NFSD To compile the NFS server support as a module, choose M here: the module will be called nfsd. If unsure, say N. +config NFSD_V2_ACL + bool + depends on NFSD + config NFSD_V3 bool "Provide NFSv3 server support" depends on NFSD @@ -1383,6 +1388,16 @@ config NFSD_V3 If you would like to include the NFSv3 server as well as the NFSv2 server, say Y here. If unsure, say Y. +config NFSD_V3_ACL + bool "Provide server support for the NFSv3 ACL protocol extension" + depends on NFSD_V3 + select NFSD_V2_ACL + help + Implement the NFSv3 ACL protocol extension for manipulating POSIX + Access Control Lists on exported file systems. NFS clients should + be compiled with the NFSv3 ACL protocol extension; see the + CONFIG_NFS_V3_ACL option. If unsure, say N. + config NFSD_V4 bool "Provide NFSv4 server support (EXPERIMENTAL)" depends on NFSD_V3 && EXPERIMENTAL @@ -1427,6 +1442,15 @@ config LOCKD_V4 config EXPORTFS tristate +config NFS_ACL_SUPPORT + tristate + select FS_POSIX_ACL + +config NFS_COMMON + bool + depends on NFSD || NFS_FS + default y + config SUNRPC tristate diff --git a/fs/Makefile b/fs/Makefile index 443f2bc..fc92e59 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o obj-$(CONFIG_FS_MBCACHE) += mbcache.o obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o +obj-$(CONFIG_NFS_COMMON) += nfs_common/ obj-$(CONFIG_QUOTA) += dquot.o obj-$(CONFIG_QFMT_V1) += quota_v1.o diff --git a/fs/nfs_common/Makefile b/fs/nfs_common/Makefile new file mode 100644 index 0000000..f689ed8 --- /dev/null +++ b/fs/nfs_common/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for Linux filesystem routines that are shared by client and server. +# + +obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o + +nfs_acl-objs := nfsacl.o diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c new file mode 100644 index 0000000..18c58c3 --- /dev/null +++ b/fs/nfs_common/nfsacl.c @@ -0,0 +1,257 @@ +/* + * fs/nfs_common/nfsacl.c + * + * Copyright (C) 2002-2003 Andreas Gruenbacher + */ + +/* + * The Solaris nfsacl protocol represents some ACLs slightly differently + * than POSIX 1003.1e draft 17 does (and we do): + * + * - Minimal ACLs always have an ACL_MASK entry, so they have + * four instead of three entries. + * - The ACL_MASK entry in such minimal ACLs always has the same + * permissions as the ACL_GROUP_OBJ entry. (In extended ACLs + * the ACL_MASK and ACL_GROUP_OBJ entries may differ.) + * - The identifier fields of the ACL_USER_OBJ and ACL_GROUP_OBJ + * entries contain the identifiers of the owner and owning group. + * (In POSIX ACLs we always set them to ACL_UNDEFINED_ID). + * - ACL entries in the kernel are kept sorted in ascending order + * of (e_tag, e_id). Solaris ACLs are unsorted. + */ + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(nfsacl_encode); +EXPORT_SYMBOL(nfsacl_decode); + +struct nfsacl_encode_desc { + struct xdr_array2_desc desc; + unsigned int count; + struct posix_acl *acl; + int typeflag; + uid_t uid; + gid_t gid; +}; + +static int +xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) +{ + struct nfsacl_encode_desc *nfsacl_desc = + (struct nfsacl_encode_desc *) desc; + u32 *p = (u32 *) elem; + + if (nfsacl_desc->count < nfsacl_desc->acl->a_count) { + struct posix_acl_entry *entry = + &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; + + *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag); + switch(entry->e_tag) { + case ACL_USER_OBJ: + *p++ = htonl(nfsacl_desc->uid); + break; + case ACL_GROUP_OBJ: + *p++ = htonl(nfsacl_desc->gid); + break; + case ACL_USER: + case ACL_GROUP: + *p++ = htonl(entry->e_id); + break; + default: /* Solaris depends on that! */ + *p++ = 0; + break; + } + *p++ = htonl(entry->e_perm & S_IRWXO); + } else { + const struct posix_acl_entry *pa, *pe; + int group_obj_perm = ACL_READ|ACL_WRITE|ACL_EXECUTE; + + FOREACH_ACL_ENTRY(pa, nfsacl_desc->acl, pe) { + if (pa->e_tag == ACL_GROUP_OBJ) { + group_obj_perm = pa->e_perm & S_IRWXO; + break; + } + } + /* fake up ACL_MASK entry */ + *p++ = htonl(ACL_MASK | nfsacl_desc->typeflag); + *p++ = htonl(0); + *p++ = htonl(group_obj_perm); + } + + return 0; +} + +unsigned int +nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, + struct posix_acl *acl, int encode_entries, int typeflag) +{ + int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0; + struct nfsacl_encode_desc nfsacl_desc = { + .desc = { + .elem_size = 12, + .array_len = encode_entries ? entries : 0, + .xcode = xdr_nfsace_encode, + }, + .acl = acl, + .typeflag = typeflag, + .uid = inode->i_uid, + .gid = inode->i_gid, + }; + int err; + + if (entries > NFS_ACL_MAX_ENTRIES || + xdr_encode_word(buf, base, entries)) + return -EINVAL; + err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); + if (!err) + err = 8 + nfsacl_desc.desc.elem_size * + nfsacl_desc.desc.array_len; + return err; +} + +struct nfsacl_decode_desc { + struct xdr_array2_desc desc; + unsigned int count; + struct posix_acl *acl; +}; + +static int +xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem) +{ + struct nfsacl_decode_desc *nfsacl_desc = + (struct nfsacl_decode_desc *) desc; + u32 *p = (u32 *) elem; + struct posix_acl_entry *entry; + + if (!nfsacl_desc->acl) { + if (desc->array_len > NFS_ACL_MAX_ENTRIES) + return -EINVAL; + nfsacl_desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL); + if (!nfsacl_desc->acl) + return -ENOMEM; + nfsacl_desc->count = 0; + } + + entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; + entry->e_tag = ntohl(*p++) & ~NFS_ACL_DEFAULT; + entry->e_id = ntohl(*p++); + entry->e_perm = ntohl(*p++); + + switch(entry->e_tag) { + case ACL_USER_OBJ: + case ACL_USER: + case ACL_GROUP_OBJ: + case ACL_GROUP: + case ACL_OTHER: + if (entry->e_perm & ~S_IRWXO) + return -EINVAL; + break; + case ACL_MASK: + /* Solaris sometimes sets additonal bits in the mask */ + entry->e_perm &= S_IRWXO; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int +cmp_acl_entry(const void *x, const void *y) +{ + const struct posix_acl_entry *a = x, *b = y; + + if (a->e_tag != b->e_tag) + return a->e_tag - b->e_tag; + else if (a->e_id > b->e_id) + return 1; + else if (a->e_id < b->e_id) + return -1; + else + return 0; +} + +/* + * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL. + */ +static int +posix_acl_from_nfsacl(struct posix_acl *acl) +{ + struct posix_acl_entry *pa, *pe, + *group_obj = NULL, *mask = NULL; + + if (!acl) + return 0; + + sort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry), + cmp_acl_entry, NULL); + + /* Clear undefined identifier fields and find the ACL_GROUP_OBJ + and ACL_MASK entries. */ + FOREACH_ACL_ENTRY(pa, acl, pe) { + switch(pa->e_tag) { + case ACL_USER_OBJ: + pa->e_id = ACL_UNDEFINED_ID; + break; + case ACL_GROUP_OBJ: + pa->e_id = ACL_UNDEFINED_ID; + group_obj = pa; + break; + case ACL_MASK: + mask = pa; + /* fall through */ + case ACL_OTHER: + pa->e_id = ACL_UNDEFINED_ID; + break; + } + } + if (acl->a_count == 4 && group_obj && mask && + mask->e_perm == group_obj->e_perm) { + /* remove bogus ACL_MASK entry */ + memmove(mask, mask+1, (3 - (mask - acl->a_entries)) * + sizeof(struct posix_acl_entry)); + acl->a_count = 3; + } + return 0; +} + +unsigned int +nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, + struct posix_acl **pacl) +{ + struct nfsacl_decode_desc nfsacl_desc = { + .desc = { + .elem_size = 12, + .xcode = pacl ? xdr_nfsace_decode : NULL, + }, + }; + u32 entries; + int err; + + if (xdr_decode_word(buf, base, &entries) || + entries > NFS_ACL_MAX_ENTRIES) + return -EINVAL; + err = xdr_decode_array2(buf, base + 4, &nfsacl_desc.desc); + if (err) + return err; + if (pacl) { + if (entries != nfsacl_desc.desc.array_len || + posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) { + posix_acl_release(nfsacl_desc.acl); + return -EINVAL; + } + *pacl = nfsacl_desc.acl; + } + if (aclcnt) + *aclcnt = entries; + return 8 + nfsacl_desc.desc.elem_size * + nfsacl_desc.desc.array_len; +} diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index b8680a2..9f043f4 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile @@ -6,7 +6,9 @@ obj-$(CONFIG_NFSD) += nfsd.o nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o +nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o +nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ nfs4acl.o nfs4callback.o nfsd-objs := $(nfsd-y) diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c new file mode 100644 index 0000000..7cbf068 --- /dev/null +++ b/fs/nfsd/nfs2acl.c @@ -0,0 +1,336 @@ +/* + * linux/fs/nfsd/nfsacl.c + * + * Process version 2 NFSACL requests. + * + * Copyright (C) 2002-2003 Andreas Gruenbacher + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NFSDDBG_FACILITY NFSDDBG_PROC +#define RETURN_STATUS(st) { resp->status = (st); return (st); } + +/* + * NULL call. + */ +static int +nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) +{ + return nfs_ok; +} + +/* + * Get the Access and/or Default ACL of a file. + */ +static int nfsacld_proc_getacl(struct svc_rqst * rqstp, + struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) +{ + svc_fh *fh; + struct posix_acl *acl; + int nfserr = 0; + + dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); + + fh = fh_copy(&resp->fh, &argp->fh); + if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) + RETURN_STATUS(nfserr_inval); + + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) + RETURN_STATUS(nfserr_inval); + resp->mask = argp->mask; + + if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { + acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); + if (IS_ERR(acl)) { + int err = PTR_ERR(acl); + + if (err == -ENODATA || err == -EOPNOTSUPP) + acl = NULL; + else { + nfserr = nfserrno(err); + goto fail; + } + } + if (acl == NULL) { + /* Solaris returns the inode's minimum ACL. */ + + struct inode *inode = fh->fh_dentry->d_inode; + acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); + } + resp->acl_access = acl; + } + if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { + /* Check how Solaris handles requests for the Default ACL + of a non-directory! */ + + acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); + if (IS_ERR(acl)) { + int err = PTR_ERR(acl); + + if (err == -ENODATA || err == -EOPNOTSUPP) + acl = NULL; + else { + nfserr = nfserrno(err); + goto fail; + } + } + resp->acl_default = acl; + } + + /* resp->acl_{access,default} are released in nfssvc_release_getacl. */ + RETURN_STATUS(0); + +fail: + posix_acl_release(resp->acl_access); + posix_acl_release(resp->acl_default); + RETURN_STATUS(nfserr); +} + +/* + * Set the Access and/or Default ACL of a file. + */ +static int nfsacld_proc_setacl(struct svc_rqst * rqstp, + struct nfsd3_setaclargs *argp, + struct nfsd_attrstat *resp) +{ + svc_fh *fh; + int nfserr = 0; + + dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); + + fh = fh_copy(&resp->fh, &argp->fh); + nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); + + if (!nfserr) { + nfserr = nfserrno( nfsd_set_posix_acl( + fh, ACL_TYPE_ACCESS, argp->acl_access) ); + } + if (!nfserr) { + nfserr = nfserrno( nfsd_set_posix_acl( + fh, ACL_TYPE_DEFAULT, argp->acl_default) ); + } + + /* argp->acl_{access,default} may have been allocated in + nfssvc_decode_setaclargs. */ + posix_acl_release(argp->acl_access); + posix_acl_release(argp->acl_default); + return nfserr; +} + +/* + * Check file attributes + */ +static int nfsacld_proc_getattr(struct svc_rqst * rqstp, + struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) +{ + dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); + + fh_copy(&resp->fh, &argp->fh); + return fh_verify(rqstp, &resp->fh, 0, MAY_NOP); +} + +/* + * Check file access + */ +static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, + struct nfsd3_accessres *resp) +{ + int nfserr; + + dprintk("nfsd: ACCESS(2acl) %s 0x%x\n", + SVCFH_fmt(&argp->fh), + argp->access); + + fh_copy(&resp->fh, &argp->fh); + resp->access = argp->access; + nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); + return nfserr; +} + +/* + * XDR decode functions + */ +static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_getaclargs *argp) +{ + if (!(p = nfs2svc_decode_fh(p, &argp->fh))) + return 0; + argp->mask = ntohl(*p); p++; + + return xdr_argsize_check(rqstp, p); +} + + +static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_setaclargs *argp) +{ + struct kvec *head = rqstp->rq_arg.head; + unsigned int base; + int n; + + if (!(p = nfs2svc_decode_fh(p, &argp->fh))) + return 0; + argp->mask = ntohl(*p++); + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || + !xdr_argsize_check(rqstp, p)) + return 0; + + base = (char *)p - (char *)head->iov_base; + n = nfsacl_decode(&rqstp->rq_arg, base, NULL, + (argp->mask & NFS_ACL) ? + &argp->acl_access : NULL); + if (n > 0) + n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, + (argp->mask & NFS_DFACL) ? + &argp->acl_default : NULL); + return (n > 0); +} + +static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p, + struct nfsd_fhandle *argp) +{ + if (!(p = nfs2svc_decode_fh(p, &argp->fh))) + return 0; + return xdr_argsize_check(rqstp, p); +} + +static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_accessargs *argp) +{ + if (!(p = nfs2svc_decode_fh(p, &argp->fh))) + return 0; + argp->access = ntohl(*p++); + + return xdr_argsize_check(rqstp, p); +} + +/* + * XDR encode functions + */ + +/* GETACL */ +static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_getaclres *resp) +{ + struct dentry *dentry = resp->fh.fh_dentry; + struct inode *inode = dentry->d_inode; + int w = nfsacl_size( + (resp->mask & NFS_ACL) ? resp->acl_access : NULL, + (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); + struct kvec *head = rqstp->rq_res.head; + unsigned int base; + int n; + + if (dentry == NULL || dentry->d_inode == NULL) + return 0; + inode = dentry->d_inode; + + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); + *p++ = htonl(resp->mask); + if (!xdr_ressize_check(rqstp, p)) + return 0; + base = (char *)p - (char *)head->iov_base; + + rqstp->rq_res.page_len = w; + while (w > 0) { + if (!svc_take_res_page(rqstp)) + return 0; + w -= PAGE_SIZE; + } + + n = nfsacl_encode(&rqstp->rq_res, base, inode, + resp->acl_access, + resp->mask & NFS_ACL, 0); + if (n > 0) + n = nfsacl_encode(&rqstp->rq_res, base + n, inode, + resp->acl_default, + resp->mask & NFS_DFACL, + NFS_ACL_DEFAULT); + if (n <= 0) + return 0; + return 1; +} + +static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p, + struct nfsd_attrstat *resp) +{ + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); + return xdr_ressize_check(rqstp, p); +} + +/* ACCESS */ +static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_accessres *resp) +{ + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); + *p++ = htonl(resp->access); + return xdr_ressize_check(rqstp, p); +} + +/* + * XDR release functions + */ +static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_getaclres *resp) +{ + fh_put(&resp->fh); + posix_acl_release(resp->acl_access); + posix_acl_release(resp->acl_default); + return 1; +} + +static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p, + struct nfsd_fhandle *resp) +{ + fh_put(&resp->fh); + return 1; +} + +#define nfsaclsvc_decode_voidargs NULL +#define nfsaclsvc_encode_voidres NULL +#define nfsaclsvc_release_void NULL +#define nfsd3_fhandleargs nfsd_fhandle +#define nfsd3_attrstatres nfsd_attrstat +#define nfsd3_voidres nfsd3_voidargs +struct nfsd3_voidargs { int dummy; }; + +#define PROC(name, argt, rest, relt, cache, respsize) \ + { (svc_procfunc) nfsacld_proc_##name, \ + (kxdrproc_t) nfsaclsvc_decode_##argt##args, \ + (kxdrproc_t) nfsaclsvc_encode_##rest##res, \ + (kxdrproc_t) nfsaclsvc_release_##relt, \ + sizeof(struct nfsd3_##argt##args), \ + sizeof(struct nfsd3_##rest##res), \ + 0, \ + cache, \ + respsize, \ + } + +#define ST 1 /* status*/ +#define AT 21 /* attributes */ +#define pAT (1+AT) /* post attributes - conditional */ +#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ + +static struct svc_procedure nfsd_acl_procedures2[] = { + PROC(null, void, void, void, RC_NOCACHE, ST), + PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), + PROC(setacl, setacl, attrstat, fhandle, RC_NOCACHE, ST+AT), + PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), + PROC(access, access, access, fhandle, RC_NOCACHE, ST+AT+1), +}; + +struct svc_version nfsd_acl_version2 = { + .vs_vers = 2, + .vs_nproc = 5, + .vs_proc = nfsd_acl_procedures2, + .vs_dispatch = nfsd_dispatch, + .vs_xdrsize = NFS3_SVC_XDRSIZE, +}; diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c new file mode 100644 index 0000000..64ba405 --- /dev/null +++ b/fs/nfsd/nfs3acl.c @@ -0,0 +1,267 @@ +/* + * linux/fs/nfsd/nfs3acl.c + * + * Process version 3 NFSACL requests. + * + * Copyright (C) 2002-2003 Andreas Gruenbacher + */ + +#include +#include +#include +#include +#include +#include +#include + +#define RETURN_STATUS(st) { resp->status = (st); return (st); } + +/* + * NULL call. + */ +static int +nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) +{ + return nfs_ok; +} + +/* + * Get the Access and/or Default ACL of a file. + */ +static int nfsd3_proc_getacl(struct svc_rqst * rqstp, + struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) +{ + svc_fh *fh; + struct posix_acl *acl; + int nfserr = 0; + + fh = fh_copy(&resp->fh, &argp->fh); + if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) + RETURN_STATUS(nfserr_inval); + + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) + RETURN_STATUS(nfserr_inval); + resp->mask = argp->mask; + + if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { + acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); + if (IS_ERR(acl)) { + int err = PTR_ERR(acl); + + if (err == -ENODATA || err == -EOPNOTSUPP) + acl = NULL; + else { + nfserr = nfserrno(err); + goto fail; + } + } + if (acl == NULL) { + /* Solaris returns the inode's minimum ACL. */ + + struct inode *inode = fh->fh_dentry->d_inode; + acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); + } + resp->acl_access = acl; + } + if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { + /* Check how Solaris handles requests for the Default ACL + of a non-directory! */ + + acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); + if (IS_ERR(acl)) { + int err = PTR_ERR(acl); + + if (err == -ENODATA || err == -EOPNOTSUPP) + acl = NULL; + else { + nfserr = nfserrno(err); + goto fail; + } + } + resp->acl_default = acl; + } + + /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */ + RETURN_STATUS(0); + +fail: + posix_acl_release(resp->acl_access); + posix_acl_release(resp->acl_default); + RETURN_STATUS(nfserr); +} + +/* + * Set the Access and/or Default ACL of a file. + */ +static int nfsd3_proc_setacl(struct svc_rqst * rqstp, + struct nfsd3_setaclargs *argp, + struct nfsd3_attrstat *resp) +{ + svc_fh *fh; + int nfserr = 0; + + fh = fh_copy(&resp->fh, &argp->fh); + nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); + + if (!nfserr) { + nfserr = nfserrno( nfsd_set_posix_acl( + fh, ACL_TYPE_ACCESS, argp->acl_access) ); + } + if (!nfserr) { + nfserr = nfserrno( nfsd_set_posix_acl( + fh, ACL_TYPE_DEFAULT, argp->acl_default) ); + } + + /* argp->acl_{access,default} may have been allocated in + nfs3svc_decode_setaclargs. */ + posix_acl_release(argp->acl_access); + posix_acl_release(argp->acl_default); + RETURN_STATUS(nfserr); +} + +/* + * XDR decode functions + */ +static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_getaclargs *args) +{ + if (!(p = nfs3svc_decode_fh(p, &args->fh))) + return 0; + args->mask = ntohl(*p); p++; + + return xdr_argsize_check(rqstp, p); +} + + +static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_setaclargs *args) +{ + struct kvec *head = rqstp->rq_arg.head; + unsigned int base; + int n; + + if (!(p = nfs3svc_decode_fh(p, &args->fh))) + return 0; + args->mask = ntohl(*p++); + if (args->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || + !xdr_argsize_check(rqstp, p)) + return 0; + + base = (char *)p - (char *)head->iov_base; + n = nfsacl_decode(&rqstp->rq_arg, base, NULL, + (args->mask & NFS_ACL) ? + &args->acl_access : NULL); + if (n > 0) + n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, + (args->mask & NFS_DFACL) ? + &args->acl_default : NULL); + return (n > 0); +} + +/* + * XDR encode functions + */ + +/* GETACL */ +static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_getaclres *resp) +{ + struct dentry *dentry = resp->fh.fh_dentry; + + p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); + if (resp->status == 0 && dentry && dentry->d_inode) { + struct inode *inode = dentry->d_inode; + int w = nfsacl_size( + (resp->mask & NFS_ACL) ? resp->acl_access : NULL, + (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); + struct kvec *head = rqstp->rq_res.head; + unsigned int base; + int n; + + *p++ = htonl(resp->mask); + if (!xdr_ressize_check(rqstp, p)) + return 0; + base = (char *)p - (char *)head->iov_base; + + rqstp->rq_res.page_len = w; + while (w > 0) { + if (!svc_take_res_page(rqstp)) + return 0; + w -= PAGE_SIZE; + } + + n = nfsacl_encode(&rqstp->rq_res, base, inode, + resp->acl_access, + resp->mask & NFS_ACL, 0); + if (n > 0) + n = nfsacl_encode(&rqstp->rq_res, base + n, inode, + resp->acl_default, + resp->mask & NFS_DFACL, + NFS_ACL_DEFAULT); + if (n <= 0) + return 0; + } else + if (!xdr_ressize_check(rqstp, p)) + return 0; + + return 1; +} + +/* SETACL */ +static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_attrstat *resp) +{ + p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); + + return xdr_ressize_check(rqstp, p); +} + +/* + * XDR release functions + */ +static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p, + struct nfsd3_getaclres *resp) +{ + fh_put(&resp->fh); + posix_acl_release(resp->acl_access); + posix_acl_release(resp->acl_default); + return 1; +} + +#define nfs3svc_decode_voidargs NULL +#define nfs3svc_release_void NULL +#define nfsd3_setaclres nfsd3_attrstat +#define nfsd3_voidres nfsd3_voidargs +struct nfsd3_voidargs { int dummy; }; + +#define PROC(name, argt, rest, relt, cache, respsize) \ + { (svc_procfunc) nfsd3_proc_##name, \ + (kxdrproc_t) nfs3svc_decode_##argt##args, \ + (kxdrproc_t) nfs3svc_encode_##rest##res, \ + (kxdrproc_t) nfs3svc_release_##relt, \ + sizeof(struct nfsd3_##argt##args), \ + sizeof(struct nfsd3_##rest##res), \ + 0, \ + cache, \ + respsize, \ + } + +#define ST 1 /* status*/ +#define AT 21 /* attributes */ +#define pAT (1+AT) /* post attributes - conditional */ +#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ + +static struct svc_procedure nfsd_acl_procedures3[] = { + PROC(null, void, void, void, RC_NOCACHE, ST), + PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), + PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT), +}; + +struct svc_version nfsd_acl_version3 = { + .vs_vers = 3, + .vs_nproc = 3, + .vs_proc = nfsd_acl_procedures3, + .vs_dispatch = nfsd_dispatch, + .vs_xdrsize = NFS3_SVC_XDRSIZE, +}; + diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 11f8068..e0e134d 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -71,6 +71,12 @@ decode_fh(u32 *p, struct svc_fh *fhp) return p + XDR_QUADLEN(size); } +/* Helper function for NFSv3 ACL code */ +u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp) +{ + return decode_fh(p, fhp); +} + static inline u32 * encode_fh(u32 *p, struct svc_fh *fhp) { @@ -233,6 +239,13 @@ encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) return p; } +/* Helper for NFSv3 ACLs */ +u32 * +nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +{ + return encode_post_op_attr(rqstp, p, fhp); +} + /* * Enocde weak cache consistency data */ diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 02ded7c..79b25b1 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -31,6 +31,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_SVC @@ -362,6 +363,31 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) return 1; } +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) +static struct svc_stat nfsd_acl_svcstats; +static struct svc_version * nfsd_acl_version[] = { + [2] = &nfsd_acl_version2, + [3] = &nfsd_acl_version3, +}; + +#define NFSD_ACL_NRVERS (sizeof(nfsd_acl_version)/sizeof(nfsd_acl_version[0])) +static struct svc_program nfsd_acl_program = { + .pg_prog = NFS_ACL_PROGRAM, + .pg_nvers = NFSD_ACL_NRVERS, + .pg_vers = nfsd_acl_version, + .pg_name = "nfsd", + .pg_stats = &nfsd_acl_svcstats, +}; + +static struct svc_stat nfsd_acl_svcstats = { + .program = &nfsd_acl_program, +}; + +#define nfsd_acl_program_p &nfsd_acl_program +#else +#define nfsd_acl_program_p NULL +#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ + extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; static struct svc_version * nfsd_version[] = { @@ -376,6 +402,7 @@ static struct svc_version * nfsd_version[] = { #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) struct svc_program nfsd_program = { + .pg_next = nfsd_acl_program_p, .pg_prog = NFS_PROGRAM, /* program number */ .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ .pg_vers = nfsd_version, /* version table */ diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 948b082..b45999f 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -49,6 +49,12 @@ decode_fh(u32 *p, struct svc_fh *fhp) return p + (NFS_FHSIZE >> 2); } +/* Helper function for NFSv2 ACL code */ +u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp) +{ + return decode_fh(p, fhp); +} + static inline u32 * encode_fh(u32 *p, struct svc_fh *fhp) { @@ -190,6 +196,11 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) return p; } +/* Helper function for NFSv2 ACL code */ +u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) +{ + return encode_fattr(rqstp, p, fhp); +} /* * XDR decode functions diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index e3e9d21..ae3940d 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -46,8 +46,9 @@ #include #include #include -#ifdef CONFIG_NFSD_V4 +#include #include +#ifdef CONFIG_NFSD_V4 #include #include #include @@ -1857,3 +1858,107 @@ nfsd_racache_init(int cache_size) nfsdstats.ra_size = cache_size; return 0; } + +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) +struct posix_acl * +nfsd_get_posix_acl(struct svc_fh *fhp, int type) +{ + struct inode *inode = fhp->fh_dentry->d_inode; + char *name; + void *value = NULL; + ssize_t size; + struct posix_acl *acl; + + if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr) + return ERR_PTR(-EOPNOTSUPP); + switch(type) { + case ACL_TYPE_ACCESS: + name = XATTR_NAME_ACL_ACCESS; + break; + case ACL_TYPE_DEFAULT: + name = XATTR_NAME_ACL_DEFAULT; + break; + default: + return ERR_PTR(-EOPNOTSUPP); + } + + size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0); + + if (size < 0) { + acl = ERR_PTR(size); + goto getout; + } else if (size > 0) { + value = kmalloc(size, GFP_KERNEL); + if (!value) { + acl = ERR_PTR(-ENOMEM); + goto getout; + } + size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size); + if (size < 0) { + acl = ERR_PTR(size); + goto getout; + } + } + acl = posix_acl_from_xattr(value, size); + +getout: + kfree(value); + return acl; +} + +int +nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) +{ + struct inode *inode = fhp->fh_dentry->d_inode; + char *name; + void *value = NULL; + size_t size; + int error; + + if (!IS_POSIXACL(inode) || !inode->i_op || + !inode->i_op->setxattr || !inode->i_op->removexattr) + return -EOPNOTSUPP; + switch(type) { + case ACL_TYPE_ACCESS: + name = XATTR_NAME_ACL_ACCESS; + break; + case ACL_TYPE_DEFAULT: + name = XATTR_NAME_ACL_DEFAULT; + break; + default: + return -EOPNOTSUPP; + } + + if (acl && acl->a_count) { + size = xattr_acl_size(acl->a_count); + value = kmalloc(size, GFP_KERNEL); + if (!value) + return -ENOMEM; + size = posix_acl_to_xattr(acl, value, size); + if (size < 0) { + error = size; + goto getout; + } + } else + size = 0; + + if (!fhp->fh_locked) + fh_lock(fhp); /* unlocking is done automatically */ + if (size) + error = inode->i_op->setxattr(fhp->fh_dentry, name, + value, size, 0); + else { + if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT) + error = 0; + else { + error = inode->i_op->removexattr(fhp->fh_dentry, name); + if (error == -ENODATA) + error = 0; + } + } + +getout: + kfree(value); + return error; +} +#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ diff --git a/include/linux/nfsacl.h b/include/linux/nfsacl.h new file mode 100644 index 0000000..54487a9 --- /dev/null +++ b/include/linux/nfsacl.h @@ -0,0 +1,58 @@ +/* + * File: linux/nfsacl.h + * + * (C) 2003 Andreas Gruenbacher + */ +#ifndef __LINUX_NFSACL_H +#define __LINUX_NFSACL_H + +#define NFS_ACL_PROGRAM 100227 + +#define ACLPROC2_GETACL 1 +#define ACLPROC2_SETACL 2 +#define ACLPROC2_GETATTR 3 +#define ACLPROC2_ACCESS 4 + +#define ACLPROC3_GETACL 1 +#define ACLPROC3_SETACL 2 + + +/* Flags for the getacl/setacl mode */ +#define NFS_ACL 0x0001 +#define NFS_ACLCNT 0x0002 +#define NFS_DFACL 0x0004 +#define NFS_DFACLCNT 0x0008 + +/* Flag for Default ACL entries */ +#define NFS_ACL_DEFAULT 0x1000 + +#ifdef __KERNEL__ + +#include + +/* Maximum number of ACL entries over NFS */ +#define NFS_ACL_MAX_ENTRIES 1024 + +#define NFSACL_MAXWORDS (2*(2+3*NFS_ACL_MAX_ENTRIES)) +#define NFSACL_MAXPAGES ((2*(8+12*NFS_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \ + >> PAGE_SHIFT) + +static inline unsigned int +nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default) +{ + unsigned int w = 16; + w += max(acl_access ? (int)acl_access->a_count : 3, 4) * 12; + if (acl_default) + w += max((int)acl_default->a_count, 4) * 12; + return w; +} + +extern unsigned int +nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, + struct posix_acl *acl, int encode_entries, int typeflag); +extern unsigned int +nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, + struct posix_acl **pacl); + +#endif /* __KERNEL__ */ +#endif /* __LINUX_NFSACL_H */ diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 8f85d9a..4bf931d 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -124,6 +125,21 @@ int nfsd_statfs(struct svc_rqst *, struct svc_fh *, int nfsd_notify_change(struct inode *, struct iattr *); int nfsd_permission(struct svc_export *, struct dentry *, int); +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) +#ifdef CONFIG_NFSD_V2_ACL +extern struct svc_version nfsd_acl_version2; +#else +#define nfsd_acl_version2 NULL +#endif +#ifdef CONFIG_NFSD_V3_ACL +extern struct svc_version nfsd_acl_version3; +#else +#define nfsd_acl_version3 NULL +#endif +struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); +int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); +#endif + /* * NFSv4 State diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h index ecccef7..130d4f5 100644 --- a/include/linux/nfsd/xdr.h +++ b/include/linux/nfsd/xdr.h @@ -169,4 +169,8 @@ int nfssvc_encode_entry(struct readdir_cd *, const char *name, int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); +/* Helper functions for NFSv2 ACL code */ +u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp); +u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp); + #endif /* LINUX_NFSD_H */ diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h index 0ae9e0e..21e18ce 100644 --- a/include/linux/nfsd/xdr3.h +++ b/include/linux/nfsd/xdr3.h @@ -110,6 +110,19 @@ struct nfsd3_commitargs { __u32 count; }; +struct nfsd3_getaclargs { + struct svc_fh fh; + int mask; +}; + +struct posix_acl; +struct nfsd3_setaclargs { + struct svc_fh fh; + int mask; + struct posix_acl *acl_access; + struct posix_acl *acl_default; +}; + struct nfsd3_attrstat { __u32 status; struct svc_fh fh; @@ -209,6 +222,14 @@ struct nfsd3_commitres { struct svc_fh fh; }; +struct nfsd3_getaclres { + __u32 status; + struct svc_fh fh; + int mask; + struct posix_acl *acl_access; + struct posix_acl *acl_default; +}; + /* dummy type for release */ struct nfsd3_fhandle_pair { __u32 dummy; @@ -241,6 +262,7 @@ union nfsd3_xdrstore { struct nfsd3_fsinfores fsinfores; struct nfsd3_pathconfres pathconfres; struct nfsd3_commitres commitres; + struct nfsd3_getaclres getaclres; }; #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) @@ -316,6 +338,10 @@ int nfs3svc_encode_entry(struct readdir_cd *, const char *name, int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int); +/* Helper functions for NFSv3 ACL code */ +u32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, + struct svc_fh *fhp); +u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp); #endif /* _LINUX_NFSD_XDR3_H */ diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index facb944..5af8800 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -185,6 +185,17 @@ xdr_ressize_check(struct svc_rqst *rqstp, u32 *p) return vec->iov_len <= PAGE_SIZE; } +static inline struct page * +svc_take_res_page(struct svc_rqst *rqstp) +{ + if (rqstp->rq_arghi <= rqstp->rq_argused) + return NULL; + rqstp->rq_arghi--; + rqstp->rq_respages[rqstp->rq_resused] = + rqstp->rq_argpages[rqstp->rq_arghi]; + return rqstp->rq_respages[rqstp->rq_resused++]; +} + static inline int svc_take_page(struct svc_rqst *rqstp) { if (rqstp->rq_arghi <= rqstp->rq_argused) -- cgit v0.10.2 From b7fa0554cf1ba6d6895cd0a5b02989a26e0bc704 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 22 Jun 2005 17:16:27 +0000 Subject: [PATCH] NFS: Add support for NFSv3 ACLs This adds acl support fo nfs clients via the NFSACL protocol extension, by implementing the getxattr, listxattr, setxattr, and removexattr iops for the system.posix_acl_access and system.posix_acl_default attributes. This patch implements a dumb version that uses no caching (and thus adds some overhead). (Another patch in this patchset adds caching as well.) Signed-off-by: Andreas Gruenbacher Acked-by: Olaf Kirch Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust diff --git a/fs/Kconfig b/fs/Kconfig index d44b04d..a7c0cc3 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1268,6 +1268,7 @@ config NFS_FS depends on INET select LOCKD select SUNRPC + select NFS_ACL_SUPPORT if NFS_V3_ACL help If you are connected to some other (usually local) Unix computer (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing @@ -1310,6 +1311,16 @@ config NFS_V3 If unsure, say Y. +config NFS_V3_ACL + bool "Provide client support for the NFSv3 ACL protocol extension" + depends on NFS_V3 + help + Implement the NFSv3 ACL protocol extension for manipulating POSIX + Access Control Lists. The server should also be compiled with + the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option. + + If unsure, say N. + config NFS_V4 bool "Provide NFSv4 client support (EXPERIMENTAL)" depends on NFS_FS && EXPERIMENTAL diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index b4baa03..8b3bb71 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -8,6 +8,7 @@ nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \ proc.o read.o symlink.o unlink.o write.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o +nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ delegation.o idmap.o \ callback.o callback_xdr.o callback_proc.o diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 5720537..2c6a959 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -75,6 +75,27 @@ struct inode_operations nfs_dir_inode_operations = { .setattr = nfs_setattr, }; +#ifdef CONFIG_NFS_V3 +struct inode_operations nfs3_dir_inode_operations = { + .create = nfs_create, + .lookup = nfs_lookup, + .link = nfs_link, + .unlink = nfs_unlink, + .symlink = nfs_symlink, + .mkdir = nfs_mkdir, + .rmdir = nfs_rmdir, + .mknod = nfs_mknod, + .rename = nfs_rename, + .permission = nfs_permission, + .getattr = nfs_getattr, + .setattr = nfs_setattr, + .listxattr = nfs3_listxattr, + .getxattr = nfs3_getxattr, + .setxattr = nfs3_setxattr, + .removexattr = nfs3_removexattr, +}; +#endif /* CONFIG_NFS_V3 */ + #ifdef CONFIG_NFS_V4 static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 55c9075..a606708 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -71,6 +71,18 @@ struct inode_operations nfs_file_inode_operations = { .setattr = nfs_setattr, }; +#ifdef CONFIG_NFS_V3 +struct inode_operations nfs3_file_inode_operations = { + .permission = nfs_permission, + .getattr = nfs_getattr, + .setattr = nfs_setattr, + .listxattr = nfs3_listxattr, + .getxattr = nfs3_getxattr, + .setxattr = nfs3_setxattr, + .removexattr = nfs3_removexattr, +}; +#endif /* CONFIG_NFS_v3 */ + /* Hack for future NFS swap support */ #ifndef IS_SWAPFILE # define IS_SWAPFILE(inode) (0) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 97b3fe7..440b9cb 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -108,6 +108,21 @@ static struct rpc_program nfs_program = { .pipe_dir_name = "/nfs", }; +#ifdef CONFIG_NFS_V3_ACL +static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; +static struct rpc_version * nfsacl_version[] = { + [3] = &nfsacl_version3, +}; + +struct rpc_program nfsacl_program = { + .name = "nfsacl", + .number = NFS_ACL_PROGRAM, + .nrvers = sizeof(nfsacl_version) / sizeof(nfsacl_version[0]), + .version = nfsacl_version, + .stats = &nfsacl_rpcstat, +}; +#endif /* CONFIG_NFS_V3_ACL */ + static inline unsigned long nfs_fattr_to_ino_t(struct nfs_fattr *fattr) { @@ -165,6 +180,9 @@ nfs_umount_begin(struct super_block *sb) /* -EIO all pending I/O */ if (!IS_ERR(rpc)) rpc_killall_tasks(rpc); + rpc = NFS_SB(sb)->client_acl; + if (!IS_ERR(rpc)) + rpc_killall_tasks(rpc); } @@ -461,8 +479,17 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) atomic_inc(&server->client->cl_count); server->client_sys = server->client; } - if (server->flags & NFS_MOUNT_VER3) { +#ifdef CONFIG_NFS_V3_ACL + if (!(server->flags & NFS_MOUNT_NOACL)) { + server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3); + /* No errors! Assume that Sun nfsacls are supported */ + if (!IS_ERR(server->client_acl)) + server->caps |= NFS_CAP_ACLS; + } +#else + server->flags &= ~NFS_MOUNT_NOACL; +#endif /* CONFIG_NFS_V3_ACL */ if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) server->namelen = NFS3_MAXNAMLEN; sb->s_time_gran = 1; @@ -546,6 +573,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) { NFS_MOUNT_NOCTO, ",nocto", "" }, { NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NONLM, ",nolock", ",lock" }, + { NFS_MOUNT_NOACL, ",noacl", "" }, { 0, NULL, NULL } }; struct proc_nfs_info *nfs_infop; @@ -1452,7 +1480,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, memset(server, 0, sizeof(struct nfs_server)); /* Zero out the NFS state stuff */ init_nfsv4_state(server); - server->client = server->client_sys = ERR_PTR(-EINVAL); + server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); root = &server->fh; if (data->flags & NFS_MOUNT_VER3) @@ -1513,6 +1541,8 @@ static void nfs_kill_super(struct super_block *s) rpc_shutdown_client(server->client); if (!IS_ERR(server->client_sys)) rpc_shutdown_client(server->client_sys); + if (!IS_ERR(server->client_acl)) + rpc_shutdown_client(server->client_acl); if (!(server->flags & NFS_MOUNT_NONLM)) lockd_down(); /* release rpc.lockd */ @@ -1794,7 +1824,7 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, memset(server, 0, sizeof(struct nfs_server)); /* Zero out the NFS state stuff */ init_nfsv4_state(server); - server->client = server->client_sys = ERR_PTR(-EINVAL); + server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); p = nfs_copy_user_string(NULL, &data->hostname, 256); if (IS_ERR(p)) diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c new file mode 100644 index 0000000..393ba79 --- /dev/null +++ b/fs/nfs/nfs3acl.c @@ -0,0 +1,303 @@ +#include +#include +#include +#include +#include +#include + +#define NFSDBG_FACILITY NFSDBG_PROC + +ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + struct inode *inode = dentry->d_inode; + struct posix_acl *acl; + int pos=0, len=0; + +# define output(s) do { \ + if (pos + sizeof(s) <= size) { \ + memcpy(buffer + pos, s, sizeof(s)); \ + pos += sizeof(s); \ + } \ + len += sizeof(s); \ + } while(0) + + acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { + output("system.posix_acl_access"); + posix_acl_release(acl); + } + + if (S_ISDIR(inode->i_mode)) { + acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { + output("system.posix_acl_default"); + posix_acl_release(acl); + } + } + +# undef output + + if (!buffer || len <= size) + return len; + return -ERANGE; +} + +ssize_t nfs3_getxattr(struct dentry *dentry, const char *name, + void *buffer, size_t size) +{ + struct inode *inode = dentry->d_inode; + struct posix_acl *acl; + int type, error = 0; + + if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) + type = ACL_TYPE_ACCESS; + else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) + type = ACL_TYPE_DEFAULT; + else + return -EOPNOTSUPP; + + acl = nfs3_proc_getacl(inode, type); + if (IS_ERR(acl)) + return PTR_ERR(acl); + else if (acl) { + if (type == ACL_TYPE_ACCESS && acl->a_count == 0) + error = -ENODATA; + else + error = posix_acl_to_xattr(acl, buffer, size); + posix_acl_release(acl); + } else + error = -ENODATA; + + return error; +} + +int nfs3_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + struct inode *inode = dentry->d_inode; + struct posix_acl *acl; + int type, error; + + if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) + type = ACL_TYPE_ACCESS; + else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) + type = ACL_TYPE_DEFAULT; + else + return -EOPNOTSUPP; + + acl = posix_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + error = nfs3_proc_setacl(inode, type, acl); + posix_acl_release(acl); + + return error; +} + +int nfs3_removexattr(struct dentry *dentry, const char *name) +{ + struct inode *inode = dentry->d_inode; + int type; + + if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) + type = ACL_TYPE_ACCESS; + else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) + type = ACL_TYPE_DEFAULT; + else + return -EOPNOTSUPP; + + return nfs3_proc_setacl(inode, type, NULL); +} + +struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) +{ + struct nfs_server *server = NFS_SERVER(inode); + struct nfs_fattr fattr; + struct page *pages[NFSACL_MAXPAGES] = { }; + struct nfs3_getaclargs args = { + .fh = NFS_FH(inode), + /* The xdr layer may allocate pages here. */ + .pages = pages, + }; + struct nfs3_getaclres res = { + .fattr = &fattr, + }; + struct posix_acl *acl = NULL; + int status, count; + + if (!nfs_server_capable(inode, NFS_CAP_ACLS)) + return ERR_PTR(-EOPNOTSUPP); + + switch (type) { + case ACL_TYPE_ACCESS: + args.mask = NFS_ACLCNT|NFS_ACL; + break; + + case ACL_TYPE_DEFAULT: + if (!S_ISDIR(inode->i_mode)) + return NULL; + args.mask = NFS_DFACLCNT|NFS_DFACL; + break; + + default: + return ERR_PTR(-EINVAL); + } + + dprintk("NFS call getacl\n"); + status = rpc_call(server->client_acl, ACLPROC3_GETACL, + &args, &res, 0); + dprintk("NFS reply getacl: %d\n", status); + + /* pages may have been allocated at the xdr layer. */ + for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) + __free_page(args.pages[count]); + + switch (status) { + case 0: + status = nfs_refresh_inode(inode, &fattr); + break; + case -EPFNOSUPPORT: + case -EPROTONOSUPPORT: + dprintk("NFS_V3_ACL extension not supported; disabling\n"); + server->caps &= ~NFS_CAP_ACLS; + case -ENOTSUPP: + status = -EOPNOTSUPP; + default: + goto getout; + } + if ((args.mask & res.mask) != args.mask) { + status = -EIO; + goto getout; + } + + if (res.acl_access != NULL) { + if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) { + posix_acl_release(res.acl_access); + res.acl_access = NULL; + } + } + + switch(type) { + case ACL_TYPE_ACCESS: + acl = res.acl_access; + res.acl_access = NULL; + break; + + case ACL_TYPE_DEFAULT: + acl = res.acl_default; + res.acl_default = NULL; + } + +getout: + posix_acl_release(res.acl_access); + posix_acl_release(res.acl_default); + + if (status != 0) { + posix_acl_release(acl); + acl = ERR_PTR(status); + } + return acl; +} + +static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, + struct posix_acl *dfacl) +{ + struct nfs_server *server = NFS_SERVER(inode); + struct nfs_fattr fattr; + struct page *pages[NFSACL_MAXPAGES] = { }; + struct nfs3_setaclargs args = { + .inode = inode, + .mask = NFS_ACL, + .acl_access = acl, + .pages = pages, + }; + int status, count; + + status = -EOPNOTSUPP; + if (!nfs_server_capable(inode, NFS_CAP_ACLS)) + goto out; + + /* We are doing this here, because XDR marshalling can only + return -ENOMEM. */ + status = -ENOSPC; + if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) + goto out; + if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES) + goto out; + if (S_ISDIR(inode->i_mode)) { + args.mask |= NFS_DFACL; + args.acl_default = dfacl; + } + + dprintk("NFS call setacl\n"); + nfs_begin_data_update(inode); + status = rpc_call(server->client_acl, ACLPROC3_SETACL, + &args, &fattr, 0); + NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS; + nfs_end_data_update(inode); + dprintk("NFS reply setacl: %d\n", status); + + /* pages may have been allocated at the xdr layer. */ + for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) + __free_page(args.pages[count]); + + switch (status) { + case 0: + status = nfs_refresh_inode(inode, &fattr); + break; + case -EPFNOSUPPORT: + case -EPROTONOSUPPORT: + dprintk("NFS_V3_ACL SETACL RPC not supported" + "(will not retry)\n"); + server->caps &= ~NFS_CAP_ACLS; + case -ENOTSUPP: + status = -EOPNOTSUPP; + } +out: + return status; +} + +int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl) +{ + struct posix_acl *alloc = NULL, *dfacl = NULL; + int status; + + if (S_ISDIR(inode->i_mode)) { + switch(type) { + case ACL_TYPE_ACCESS: + alloc = dfacl = nfs3_proc_getacl(inode, + ACL_TYPE_DEFAULT); + if (IS_ERR(alloc)) + goto fail; + break; + + case ACL_TYPE_DEFAULT: + dfacl = acl; + alloc = acl = nfs3_proc_getacl(inode, + ACL_TYPE_ACCESS); + if (IS_ERR(alloc)) + goto fail; + break; + + default: + return -EINVAL; + } + } else if (type != ACL_TYPE_ACCESS) + return -EINVAL; + + if (acl == NULL) { + alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); + if (IS_ERR(alloc)) + goto fail; + } + status = nfs3_proc_setacls(inode, acl, dfacl); + posix_acl_release(alloc); + return status; + +fail: + return PTR_ERR(alloc); +} diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 53953a7..d03bac0 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -17,6 +17,7 @@ #include #include #include +#include #define NFSDBG_FACILITY NFSDBG_PROC @@ -45,7 +46,7 @@ static inline int nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) { struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[proc], + .rpc_proc = &clnt->cl_procinfo[proc], .rpc_argp = argp, .rpc_resp = resp, }; @@ -825,8 +826,8 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) struct nfs_rpc_ops nfs_v3_clientops = { .version = 3, /* protocol version */ .dentry_ops = &nfs_dentry_operations, - .dir_inode_ops = &nfs_dir_inode_operations, - .file_inode_ops = &nfs_file_inode_operations, + .dir_inode_ops = &nfs3_dir_inode_operations, + .file_inode_ops = &nfs3_file_inode_operations, .getroot = nfs3_proc_get_root, .getattr = nfs3_proc_getattr, .setattr = nfs3_proc_setattr, diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index a3593d4..a4437fb 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -21,6 +21,7 @@ #include #include #include +#include #define NFSDBG_FACILITY NFSDBG_XDR @@ -79,6 +80,11 @@ extern int nfs_stat_to_errno(int); #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) +#define ACL3_getaclargs_sz (NFS3_fh_sz+1) +#define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3)) +#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3)) +#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) + /* * Map file type to S_IFMT bits */ @@ -627,6 +633,74 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) return 0; } +#ifdef CONFIG_NFS_V3_ACL +/* + * Encode GETACL arguments + */ +static int +nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p, + struct nfs3_getaclargs *args) +{ + struct rpc_auth *auth = req->rq_task->tk_auth; + unsigned int replen; + + p = xdr_encode_fhandle(p, args->fh); + *p++ = htonl(args->mask); + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + + if (args->mask & (NFS_ACL | NFS_DFACL)) { + /* Inline the page array */ + replen = (RPC_REPHDRSIZE + auth->au_rslack + + ACL3_getaclres_sz) << 2; + xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, + NFSACL_MAXPAGES << PAGE_SHIFT); + } + return 0; +} + +/* + * Encode SETACL arguments + */ +static int +nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p, + struct nfs3_setaclargs *args) +{ + struct xdr_buf *buf = &req->rq_snd_buf; + unsigned int base, len_in_head, len = nfsacl_size( + (args->mask & NFS_ACL) ? args->acl_access : NULL, + (args->mask & NFS_DFACL) ? args->acl_default : NULL); + int count, err; + + p = xdr_encode_fhandle(p, NFS_FH(args->inode)); + *p++ = htonl(args->mask); + base = (char *)p - (char *)buf->head->iov_base; + /* put as much of the acls into head as possible. */ + len_in_head = min_t(unsigned int, buf->head->iov_len - base, len); + len -= len_in_head; + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + len_in_head); + + for (count = 0; (count << PAGE_SHIFT) < len; count++) { + args->pages[count] = alloc_page(GFP_KERNEL); + if (!args->pages[count]) { + while (count) + __free_page(args->pages[--count]); + return -ENOMEM; + } + } + xdr_encode_pages(buf, args->pages, 0, len); + + err = nfsacl_encode(buf, base, args->inode, + (args->mask & NFS_ACL) ? + args->acl_access : NULL, 1, 0); + if (err > 0) + err = nfsacl_encode(buf, base + err, args->inode, + (args->mask & NFS_DFACL) ? + args->acl_default : NULL, 1, + NFS_ACL_DEFAULT); + return (err > 0) ? 0 : err; +} +#endif /* CONFIG_NFS_V3_ACL */ + /* * NFS XDR decode functions */ @@ -978,6 +1052,54 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) return 0; } +#ifdef CONFIG_NFS_V3_ACL +/* + * Decode GETACL reply + */ +static int +nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p, + struct nfs3_getaclres *res) +{ + struct xdr_buf *buf = &req->rq_rcv_buf; + int status = ntohl(*p++); + struct posix_acl **acl; + unsigned int *aclcnt; + int err, base; + + if (status != 0) + return -nfs_stat_to_errno(status); + p = xdr_decode_post_op_attr(p, res->fattr); + res->mask = ntohl(*p++); + if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) + return -EINVAL; + base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base; + + acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL; + aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL; + err = nfsacl_decode(buf, base, aclcnt, acl); + + acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL; + aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL; + if (err > 0) + err = nfsacl_decode(buf, base + err, aclcnt, acl); + return (err > 0) ? 0 : err; +} + +/* + * Decode setacl reply. + */ +static int +nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) +{ + int status = ntohl(*p++); + + if (status) + return -nfs_stat_to_errno(status); + xdr_decode_post_op_attr(p, fattr); + return 0; +} +#endif /* CONFIG_NFS_V3_ACL */ + #ifndef MAX # define MAX(a, b) (((a) > (b))? (a) : (b)) #endif @@ -1021,3 +1143,28 @@ struct rpc_version nfs_version3 = { .procs = nfs3_procedures }; +#ifdef CONFIG_NFS_V3_ACL +static struct rpc_procinfo nfs3_acl_procedures[] = { + [ACLPROC3_GETACL] = { + .p_proc = ACLPROC3_GETACL, + .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs, + .p_decode = (kxdrproc_t) nfs3_xdr_getaclres, + .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2, + .p_timer = 1, + }, + [ACLPROC3_SETACL] = { + .p_proc = ACLPROC3_SETACL, + .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs, + .p_decode = (kxdrproc_t) nfs3_xdr_setaclres, + .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2, + .p_timer = 0, + }, +}; + +struct rpc_version nfsacl_version3 = { + .number = 3, + .nrprocs = sizeof(nfs3_acl_procedures)/ + sizeof(nfs3_acl_procedures[0]), + .procs = nfs3_acl_procedures, +}; +#endif /* CONFIG_NFS_V3_ACL */ diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index fd5bc59..1b272a1 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -124,6 +124,7 @@ enum { Opt_soft, Opt_hard, Opt_intr, Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, + Opt_acl, Opt_noacl, /* Error token */ Opt_err }; @@ -158,6 +159,8 @@ static match_table_t __initdata tokens = { {Opt_udp, "udp"}, {Opt_tcp, "proto=tcp"}, {Opt_tcp, "tcp"}, + {Opt_acl, "acl"}, + {Opt_noacl, "noacl"}, {Opt_err, NULL} }; @@ -266,6 +269,12 @@ static int __init root_nfs_parse(char *name, char *buf) case Opt_tcp: nfs_data.flags |= NFS_MOUNT_TCP; break; + case Opt_acl: + nfs_data.flags &= ~NFS_MOUNT_NOACL; + break; + case Opt_noacl: + nfs_data.flags |= NFS_MOUNT_NOACL; + break; default : return 0; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index d2b5d7e..3a5e442 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -301,6 +301,9 @@ extern u32 root_nfs_parse_addr(char *name); /*__init*/ * linux/fs/nfs/file.c */ extern struct inode_operations nfs_file_inode_operations; +#ifdef CONFIG_NFS_V3 +extern struct inode_operations nfs3_file_inode_operations; +#endif /* CONFIG_NFS_V3 */ extern struct file_operations nfs_file_operations; extern struct address_space_operations nfs_file_aops; @@ -316,6 +319,22 @@ static inline struct rpc_cred *nfs_file_cred(struct file *file) } /* + * linux/fs/nfs/xattr.c + */ +#ifdef CONFIG_NFS_V3_ACL +extern ssize_t nfs3_listxattr(struct dentry *, char *, size_t); +extern ssize_t nfs3_getxattr(struct dentry *, const char *, void *, size_t); +extern int nfs3_setxattr(struct dentry *, const char *, + const void *, size_t, int); +extern int nfs3_removexattr (struct dentry *, const char *name); +#else +# define nfs3_listxattr NULL +# define nfs3_getxattr NULL +# define nfs3_setxattr NULL +# define nfs3_removexattr NULL +#endif + +/* * linux/fs/nfs/direct.c */ extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t, @@ -329,6 +348,9 @@ extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, * linux/fs/nfs/dir.c */ extern struct inode_operations nfs_dir_inode_operations; +#ifdef CONFIG_NFS_V3 +extern struct inode_operations nfs3_dir_inode_operations; +#endif /* CONFIG_NFS_V3 */ extern struct file_operations nfs_dir_operations; extern struct dentry_operations nfs_dentry_operations; @@ -450,6 +472,15 @@ static inline void nfs_readdata_free(struct nfs_read_data *p) extern void nfs_readdata_release(struct rpc_task *task); /* + * linux/fs/nfs3proc.c + */ +#ifdef CONFIG_NFS_V3_ACL +extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type); +extern int nfs3_proc_setacl(struct inode *inode, int type, + struct posix_acl *acl); +#endif /* CONFIG_NFS_V3_ACL */ + +/* * linux/fs/mount_clnt.c * (Used only by nfsroot module) */ diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index fc51645..3d3a305 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -10,6 +10,7 @@ struct nfs_server { struct rpc_clnt * client; /* RPC client handle */ struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */ + struct rpc_clnt * client_acl; /* ACL RPC client handle */ struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */ struct backing_dev_info backing_dev_info; int flags; /* various flags */ diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h index 0071428..659c754 100644 --- a/include/linux/nfs_mount.h +++ b/include/linux/nfs_mount.h @@ -58,6 +58,7 @@ struct nfs_mount_data { #define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ #define NFS_MOUNT_NONLM 0x0200 /* 3 */ #define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */ +#define NFS_MOUNT_NOACL 0x0800 /* 4 */ #define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */ #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ #define NFS_MOUNT_FLAGMASK 0xFFFF diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 46b206b..a2bf691 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -2,6 +2,7 @@ #define _LINUX_NFS_XDR_H #include +#include struct nfs4_fsid { __u64 major; @@ -368,6 +369,20 @@ struct nfs_readdirargs { struct page ** pages; }; +struct nfs3_getaclargs { + struct nfs_fh * fh; + int mask; + struct page ** pages; +}; + +struct nfs3_setaclargs { + struct inode * inode; + int mask; + struct posix_acl * acl_access; + struct posix_acl * acl_default; + struct page ** pages; +}; + struct nfs_diropok { struct nfs_fh * fh; struct nfs_fattr * fattr; @@ -491,6 +506,15 @@ struct nfs3_readdirres { int plus; }; +struct nfs3_getaclres { + struct nfs_fattr * fattr; + int mask; + unsigned int acl_access_count; + unsigned int acl_default_count; + struct posix_acl * acl_access; + struct posix_acl * acl_default; +}; + #ifdef CONFIG_NFS_V4 typedef u64 clientid4; @@ -748,4 +772,7 @@ extern struct rpc_version nfs_version2; extern struct rpc_version nfs_version3; extern struct rpc_version nfs_version4; +extern struct rpc_version nfsacl_version3; +extern struct rpc_program nfsacl_program; + #endif -- cgit v0.10.2 From 055ffbea0596942579b0dae71d5dab78de8135f6 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 22 Jun 2005 17:16:27 +0000 Subject: [PATCH] NFS: Fix handling of the umask when an NFSv3 default acl is present. NFSv3 has no concept of a umask on the server side: The client applies the umask locally, and sends the effective permissions to the server. This behavior is wrong when files are created in a directory that has a default ACL. In this case, the umask is supposed to be ignored, and only the default ACL determines the file's effective permissions. Usually its the server's task to conditionally apply the umask. But since the server knows nothing about the umask, we have to do it on the client side. This patch tries to fetch the parent directory's default ACL before creating a new file, computes the appropriate create mode to send to the server, and finally sets the new file's access and default acl appropriately. Many thanks to Buck Huppmann for sending the initial version of this patch, as well as for arguing why we need this change. Signed-off-by: Andreas Gruenbacher Acked-by: Olaf Kirch Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 440b9cb..50a03f1 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -490,6 +490,11 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) #else server->flags &= ~NFS_MOUNT_NOACL; #endif /* CONFIG_NFS_V3_ACL */ + /* + * The VFS shouldn't apply the umask to mode bits. We will + * do so ourselves when necessary. + */ + sb->s_flags |= MS_POSIXACL; if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) server->namelen = NFS3_MAXNAMLEN; sb->s_time_gran = 1; diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 393ba79..89b6468 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -301,3 +301,32 @@ int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl) fail: return PTR_ERR(alloc); } + +int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, + mode_t mode) +{ + struct posix_acl *dfacl, *acl; + int error = 0; + + dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT); + if (IS_ERR(dfacl)) { + error = PTR_ERR(dfacl); + return (error == -EOPNOTSUPP) ? 0 : error; + } + if (!dfacl) + return 0; + acl = posix_acl_clone(dfacl, GFP_KERNEL); + error = -ENOMEM; + if (!acl) + goto out_release_dfacl; + error = posix_acl_create_masq(acl, &mode); + if (error < 0) + goto out_release_acl; + error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ? + dfacl : NULL); +out_release_acl: + posix_acl_release(acl); +out_release_dfacl: + posix_acl_release(dfacl); + return error; +} diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index d03bac0..a9ddc196 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -314,7 +314,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, .fh = &fhandle, .fattr = &fattr }; - int status; + mode_t mode = sattr->ia_mode; + int status; dprintk("NFS call create %s\n", dentry->d_name.name); arg.createmode = NFS3_CREATE_UNCHECKED; @@ -324,6 +325,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, arg.verifier[1] = current->pid; } + sattr->ia_mode &= ~current->fs->umask; + again: dir_attr.valid = 0; fattr.valid = 0; @@ -370,6 +373,9 @@ again: nfs_refresh_inode(dentry->d_inode, &fattr); dprintk("NFS reply setattr (post-create): %d\n", status); } + if (status != 0) + goto out; + status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); out: dprintk("NFS reply create: %d\n", status); return status; @@ -539,15 +545,24 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) .fh = &fhandle, .fattr = &fattr }; - int status; + int mode = sattr->ia_mode; + int status; dprintk("NFS call mkdir %s\n", dentry->d_name.name); dir_attr.valid = 0; fattr.valid = 0; + + sattr->ia_mode &= ~current->fs->umask; + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); - if (status == 0) - status = nfs_instantiate(dentry, &fhandle, &fattr); + if (status != 0) + goto out; + status = nfs_instantiate(dentry, &fhandle, &fattr); + if (status != 0) + goto out; + status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); +out: dprintk("NFS reply mkdir: %d\n", status); return status; } @@ -642,6 +657,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, .fh = &fh, .fattr = &fattr }; + mode_t mode = sattr->ia_mode; int status; switch (sattr->ia_mode & S_IFMT) { @@ -654,12 +670,20 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, MAJOR(rdev), MINOR(rdev)); + + sattr->ia_mode &= ~current->fs->umask; + dir_attr.valid = 0; fattr.valid = 0; status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); - if (status == 0) - status = nfs_instantiate(dentry, &fh, &fattr); + if (status != 0) + goto out; + status = nfs_instantiate(dentry, &fh, &fattr); + if (status != 0) + goto out; + status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); +out: dprintk("NFS reply mknod: %d\n", status); return status; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 3a5e442..7662c51 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -478,6 +478,15 @@ extern void nfs_readdata_release(struct rpc_task *task); extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type); extern int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl); +extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, + mode_t mode); +#else +static inline int nfs3_proc_set_default_acl(struct inode *dir, + struct inode *inode, + mode_t mode) +{ + return 0; +} #endif /* CONFIG_NFS_V3_ACL */ /* -- cgit v0.10.2 From 5c6a9f7d92291c832d47e792ed1fafa44acb066e Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 22 Jun 2005 17:16:27 +0000 Subject: [PATCH] NFS: Cache the NFSv3 acls. Attach acls to inodes in the icache to avoid unnecessary GETACL RPC round-trips. As long as the client doesn't retrieve any acls itself, only the default acls of exiting directories and the default and access acls of new directories will end up in the cache, which preserves some memory compared to always caching the access and default acl of all files. Signed-off-by: Andreas Gruenbacher Acked-by: Olaf Kirch Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 89b6468..451112f 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -113,6 +113,69 @@ int nfs3_removexattr(struct dentry *dentry, const char *name) return nfs3_proc_setacl(inode, type, NULL); } +static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi) +{ + if (nfsi->acl_access != ERR_PTR(-EAGAIN)) { + posix_acl_release(nfsi->acl_access); + nfsi->acl_access = ERR_PTR(-EAGAIN); + } + if (nfsi->acl_default != ERR_PTR(-EAGAIN)) { + posix_acl_release(nfsi->acl_default); + nfsi->acl_default = ERR_PTR(-EAGAIN); + } +} + +void nfs3_forget_cached_acls(struct inode *inode) +{ + dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id, + inode->i_ino); + spin_lock(&inode->i_lock); + __nfs3_forget_cached_acls(NFS_I(inode)); + spin_unlock(&inode->i_lock); +} + +static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) +{ + struct nfs_inode *nfsi = NFS_I(inode); + struct posix_acl *acl = ERR_PTR(-EAGAIN); + + spin_lock(&inode->i_lock); + switch(type) { + case ACL_TYPE_ACCESS: + acl = nfsi->acl_access; + break; + + case ACL_TYPE_DEFAULT: + acl = nfsi->acl_default; + break; + + default: + return ERR_PTR(-EINVAL); + } + if (acl == ERR_PTR(-EAGAIN)) + acl = ERR_PTR(-EAGAIN); + else + acl = posix_acl_dup(acl); + spin_unlock(&inode->i_lock); + dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id, + inode->i_ino, type, acl); + return acl; +} + +static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, + struct posix_acl *dfacl) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id, + inode->i_ino, acl, dfacl); + spin_lock(&inode->i_lock); + __nfs3_forget_cached_acls(NFS_I(inode)); + nfsi->acl_access = posix_acl_dup(acl); + nfsi->acl_default = posix_acl_dup(dfacl); + spin_unlock(&inode->i_lock); +} + struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) { struct nfs_server *server = NFS_SERVER(inode); @@ -126,26 +189,32 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) struct nfs3_getaclres res = { .fattr = &fattr, }; - struct posix_acl *acl = NULL; + struct posix_acl *acl; int status, count; if (!nfs_server_capable(inode, NFS_CAP_ACLS)) return ERR_PTR(-EOPNOTSUPP); - switch (type) { - case ACL_TYPE_ACCESS: - args.mask = NFS_ACLCNT|NFS_ACL; - break; - - case ACL_TYPE_DEFAULT: - if (!S_ISDIR(inode->i_mode)) - return NULL; - args.mask = NFS_DFACLCNT|NFS_DFACL; - break; - - default: - return ERR_PTR(-EINVAL); - } + status = nfs_revalidate_inode(server, inode); + if (status < 0) + return ERR_PTR(status); + acl = nfs3_get_cached_acl(inode, type); + if (acl != ERR_PTR(-EAGAIN)) + return acl; + acl = NULL; + + /* + * Only get the access acl when explicitly requested: We don't + * need it for access decisions, and only some applications use + * it. Applications which request the access acl first are not + * penalized from this optimization. + */ + if (type == ACL_TYPE_ACCESS) + args.mask |= NFS_ACLCNT|NFS_ACL; + if (S_ISDIR(inode->i_mode)) + args.mask |= NFS_DFACLCNT|NFS_DFACL; + if (args.mask == 0) + return NULL; dprintk("NFS call getacl\n"); status = rpc_call(server->client_acl, ACLPROC3_GETACL, @@ -180,6 +249,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) res.acl_access = NULL; } } + nfs3_cache_acls(inode, res.acl_access, res.acl_default); switch(type) { case ACL_TYPE_ACCESS: diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index a9ddc196..7851569 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -882,4 +882,5 @@ struct nfs_rpc_ops nfs_v3_clientops = { .file_open = nfs_open, .file_release = nfs_release, .lock = nfs3_proc_lock, + .clear_acl_cache = nfs3_forget_cached_acls, }; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 7662c51..4ceac9d 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -91,6 +91,8 @@ struct nfs_open_context { */ struct nfs_delegation; +struct posix_acl; + /* * nfs fs inode data in memory */ @@ -144,6 +146,10 @@ struct nfs_inode { atomic_t data_updates; struct nfs_access_entry cache_access; +#ifdef CONFIG_NFS_V3_ACL + struct posix_acl *acl_access; + struct posix_acl *acl_default; +#endif /* * This is the cookie verifier used for NFSv3 readdir @@ -480,6 +486,7 @@ extern int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl); extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, mode_t mode); +extern void nfs3_forget_cached_acls(struct inode *inode); #else static inline int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, @@ -487,6 +494,10 @@ static inline int nfs3_proc_set_default_acl(struct inode *dir, { return 0; } + +static inline void nfs3_forget_cached_acls(struct inode *inode) +{ +} #endif /* CONFIG_NFS_V3_ACL */ /* -- cgit v0.10.2 From 458818ed76d3f495f9f32373c936456c9427f759 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:27 +0000 Subject: [PATCH] NFS: Fix up v3 ACL caching code Initialize the inode cache values correctly. Clean up __nfs3_forget_cached_acls() Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 50a03f1..8a8d57d 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1961,6 +1961,10 @@ static struct inode *nfs_alloc_inode(struct super_block *sb) if (!nfsi) return NULL; nfsi->flags = 0; +#ifdef CONFIG_NFS_V3_ACL + nfsi->acl_access = ERR_PTR(-EAGAIN); + nfsi->acl_default = ERR_PTR(-EAGAIN); +#endif #ifdef CONFIG_NFS_V4 nfsi->nfs4_acl = NULL; #endif /* CONFIG_NFS_V4 */ diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 451112f..ee3536f 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -115,11 +115,11 @@ int nfs3_removexattr(struct dentry *dentry, const char *name) static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi) { - if (nfsi->acl_access != ERR_PTR(-EAGAIN)) { + if (!IS_ERR(nfsi->acl_access)) { posix_acl_release(nfsi->acl_access); nfsi->acl_access = ERR_PTR(-EAGAIN); } - if (nfsi->acl_default != ERR_PTR(-EAGAIN)) { + if (!IS_ERR(nfsi->acl_default)) { posix_acl_release(nfsi->acl_default); nfsi->acl_default = ERR_PTR(-EAGAIN); } @@ -137,7 +137,7 @@ void nfs3_forget_cached_acls(struct inode *inode) static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) { struct nfs_inode *nfsi = NFS_I(inode); - struct posix_acl *acl = ERR_PTR(-EAGAIN); + struct posix_acl *acl = ERR_PTR(-EINVAL); spin_lock(&inode->i_lock); switch(type) { @@ -150,12 +150,13 @@ static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) break; default: - return ERR_PTR(-EINVAL); + goto out; } - if (acl == ERR_PTR(-EAGAIN)) + if (IS_ERR(acl)) acl = ERR_PTR(-EAGAIN); else acl = posix_acl_dup(acl); +out: spin_unlock(&inode->i_lock); dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id, inode->i_ino, type, acl); -- cgit v0.10.2 From 213484254c65e3c39c59df454132748b1367f816 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 22 Jun 2005 17:16:28 +0000 Subject: [PATCH] fix nfsacl pointer arithmetic and pg_class initialization bugs * Pointer arithmetic bug: p is in word units. This fixes a memory corruption with big acls. * Initialize pg_class to prevent a NULL pointer access. Signed-off-by: Andreas Gruenbacher Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index a4437fb..db4a904 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -677,7 +677,7 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p, /* put as much of the acls into head as possible. */ len_in_head = min_t(unsigned int, buf->head->iov_len - base, len); len -= len_in_head; - req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + len_in_head); + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2)); for (count = 0; (count << PAGE_SHIFT) < len; count++) { args->pages[count] = alloc_page(GFP_KERNEL); diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 79b25b1..904df60 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -376,6 +376,7 @@ static struct svc_program nfsd_acl_program = { .pg_nvers = NFSD_ACL_NRVERS, .pg_vers = nfsd_acl_version, .pg_name = "nfsd", + .pg_class = "nfsd", .pg_stats = &nfsd_acl_svcstats, }; -- cgit v0.10.2 From b7ef19560f496fd3942e41e728950e5b5c9a461b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 22 Jun 2005 17:16:28 +0000 Subject: [PATCH] NFSv4: fs/nfs/nfs4proc.c: small simplification The Coverity checker noticed that such a simplification was possible. Signed-off-by: Adrian Bunk Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 128d01c..7ff2370 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -123,7 +123,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, BUG_ON(readdir->count < 80); if (cookie > 2) { - readdir->cookie = (cookie > 2) ? cookie : 0; + readdir->cookie = cookie; memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); return; } -- cgit v0.10.2 From 3e9d41543b16e6117267edc0ca058c40f888d81a Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 22 Jun 2005 17:16:28 +0000 Subject: [PATCH] NFSv4: empty array fix Older gcc's don't like this. fs/nfs/nfs4proc.c:2194: field `data' has incomplete type Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7ff2370..3f281a8 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2191,7 +2191,7 @@ static void buf_to_pages(const void *buf, size_t buflen, struct nfs4_cached_acl { int cached; size_t len; - char data[]; + char data[0]; }; static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl) -- cgit v0.10.2 From c56c2750229154f6a1cfee533e0a911da3923b5a Mon Sep 17 00:00:00 2001 From: Reuben Farrelly Date: Wed, 22 Jun 2005 17:16:28 +0000 Subject: [PATCH] NFSv4: Fix build warning From: Reuben Farrelly With gcc-4.0: fs/nfs/nfs4proc.c:2976: error: static declaration of 'nfs4_file_inode_operations' follows non-static declaration fs/nfs/nfs4_fs.h:179: error: previous declaration of 'nfs4_file_inode_operations' was here Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index d71f416..7c6f1d6 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -176,7 +176,6 @@ struct nfs4_state_recovery_ops { extern struct dentry_operations nfs4_dentry_operations; extern struct inode_operations nfs4_dir_inode_operations; -extern struct inode_operations nfs4_file_inode_operations; /* inode.c */ extern ssize_t nfs4_getxattr(struct dentry *, const char *, void *, size_t); -- cgit v0.10.2 From 455a396710b71a743b28da2ed2185e5a9b38e26f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:28 +0000 Subject: [PATCH] NFSv4: Fix an Oops in the callback code. The changeset "trond.myklebust@fys.uio.no|ChangeSet|20050322152404|16979" (RPC: Ensure XDR iovec length is initialized correctly in call_header) causes the NFSv4 callback code to BUG() due to an incorrectly initialized scratch buffer. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index c99677e..7c33b9a 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -411,7 +411,6 @@ static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); - rqstp->rq_res.head[0].iov_len = PAGE_SIZE; xdr_init_encode(&xdr_out, &rqstp->rq_res, p); decode_compound_hdr_arg(&xdr_in, &hdr_arg); -- cgit v0.10.2 From 14b218a8e4f110206c46e586a3da372f665631e7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:28 +0000 Subject: [PATCH] RPC: Ensure rpc calls respects the RPC_NOINTR flag For internal purposes, the rpc_clnt_sigmask() call is replaced by a call to rpc_task_sigmask(), which ensures that the current task sigmask respects both the client cl_intr flag and the per-task NOINTR flag. Problem noted by Jiaying Zhang. Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index c979fcf..f17e615 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -378,38 +378,41 @@ rpc_default_callback(struct rpc_task *task) } /* - * Export the signal mask handling for aysnchronous code that + * Export the signal mask handling for synchronous code that * sleeps on RPC calls */ +#define RPC_INTR_SIGNALS (sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGKILL)) +static void rpc_save_sigmask(sigset_t *oldset, int intr) +{ + unsigned long sigallow = 0; + sigset_t sigmask; + + /* Block all signals except those listed in sigallow */ + if (intr) + sigallow |= RPC_INTR_SIGNALS; + siginitsetinv(&sigmask, sigallow); + sigprocmask(SIG_BLOCK, &sigmask, oldset); +} + +static inline void rpc_task_sigmask(struct rpc_task *task, sigset_t *oldset) +{ + rpc_save_sigmask(oldset, !RPC_TASK_UNINTERRUPTIBLE(task)); +} + +static inline void rpc_restore_sigmask(sigset_t *oldset) +{ + sigprocmask(SIG_SETMASK, oldset, NULL); +} + void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset) { - unsigned long sigallow = sigmask(SIGKILL); - unsigned long irqflags; - - /* Turn off various signals */ - if (clnt->cl_intr) { - struct k_sigaction *action = current->sighand->action; - if (action[SIGINT-1].sa.sa_handler == SIG_DFL) - sigallow |= sigmask(SIGINT); - if (action[SIGQUIT-1].sa.sa_handler == SIG_DFL) - sigallow |= sigmask(SIGQUIT); - } - spin_lock_irqsave(¤t->sighand->siglock, irqflags); - *oldset = current->blocked; - siginitsetinv(¤t->blocked, sigallow & ~oldset->sig[0]); - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); + rpc_save_sigmask(oldset, clnt->cl_intr); } void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) { - unsigned long irqflags; - - spin_lock_irqsave(¤t->sighand->siglock, irqflags); - current->blocked = *oldset; - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); + rpc_restore_sigmask(oldset); } /* @@ -427,26 +430,26 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) BUG_ON(flags & RPC_TASK_ASYNC); - rpc_clnt_sigmask(clnt, &oldset); - status = -ENOMEM; task = rpc_new_task(clnt, NULL, flags); if (task == NULL) goto out; + /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */ + rpc_task_sigmask(task, &oldset); + rpc_call_setup(task, msg, 0); /* Set up the call info struct and execute the task */ - if (task->tk_status == 0) + if (task->tk_status == 0) { status = rpc_execute(task); - else { + } else { status = task->tk_status; rpc_release_task(task); } + rpc_restore_sigmask(&oldset); out: - rpc_clnt_sigunmask(clnt, &oldset); - return status; } @@ -467,8 +470,6 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, flags |= RPC_TASK_ASYNC; - rpc_clnt_sigmask(clnt, &oldset); - /* Create/initialize a new RPC task */ if (!callback) callback = rpc_default_callback; @@ -477,6 +478,9 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, goto out; task->tk_calldata = data; + /* Mask signals on GSS_AUTH upcalls */ + rpc_task_sigmask(task, &oldset); + rpc_call_setup(task, msg, 0); /* Set up the call info struct and execute the task */ @@ -486,9 +490,8 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, else rpc_release_task(task); + rpc_restore_sigmask(&oldset); out: - rpc_clnt_sigunmask(clnt, &oldset); - return status; } @@ -666,7 +669,7 @@ call_allocate(struct rpc_task *task) return; printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); - if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) { + if (RPC_IS_ASYNC(task) || !signalled()) { xprt_release(task); task->tk_action = call_reserve; rpc_delay(task, HZ>>4); -- cgit v0.10.2 From 0f9dc2b16884bb5957d010ed8e9114e771a05916 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:28 +0000 Subject: [PATCH] RPC: Clean up socket autodisconnect Cancel autodisconnect requests inside xprt_transmit() in order to avoid races. Use more efficient del_singleshot_timer_sync() Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index ef941e7..a74a128 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1240,6 +1240,8 @@ xprt_transmit(struct rpc_task *task) list_add_tail(&req->rq_list, &xprt->recv); spin_unlock_bh(&xprt->sock_lock); xprt_reset_majortimeo(req); + /* Turn off autodisconnect */ + del_singleshot_timer_sync(&xprt->timer); } } else if (!req->rq_bytes_sent) return; @@ -1370,8 +1372,6 @@ xprt_reserve(struct rpc_task *task) spin_lock(&xprt->xprt_lock); do_xprt_reserve(task); spin_unlock(&xprt->xprt_lock); - if (task->tk_rqstp) - del_timer_sync(&xprt->timer); } } -- cgit v0.10.2 From 20e5ac828dfd23b9080159c62a34f32d2dcd92fc Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 22 Jun 2005 17:16:28 +0000 Subject: [PATCH] RPC: TCP reconnects are too slow When the network layer reports a connection close, the RPC task waiting to reconnect should be notified so it can retry immediately instead of waiting for the normal connection establishment timeout. This reverts a change made in 2.6.6 as part of adding client support for RPC over TCP socket idle timeouts. Test-plan: Destructive testing with NFS over TCP mounts. Version: Fri, 29 Apr 2005 15:31:46 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index a74a128..2b8789c 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1101,8 +1101,7 @@ tcp_state_change(struct sock *sk) case TCP_SYN_RECV: break; default: - if (xprt_test_and_clear_connected(xprt)) - rpc_wake_up_status(&xprt->pending, -ENOTCONN); + xprt_disconnect(xprt); break; } out: -- cgit v0.10.2 From ae3884621bf5b4caff7785b9a417f262202965b2 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 22 Jun 2005 17:16:28 +0000 Subject: [PATCH] RPC: kick off socket connect operations faster Make the socket transport kick the event queue to start socket connects immediately. This should improve responsiveness of applications that are sensitive to slow mount operations (like automounters). We are now also careful to cancel the connect worker before destroying the xprt. This eliminates a race where xprt_destroy can finish before the connect worker is even allowed to run. Test-plan: Destructive testing (unplugging the network temporarily). Connectathon with UDP and TCP. Hard-code impossibly small connect timeout. Version: Fri, 29 Apr 2005 15:32:01 -0400 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 2b8789c..eca9240 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -569,8 +569,11 @@ void xprt_connect(struct rpc_task *task) if (xprt->sock != NULL) schedule_delayed_work(&xprt->sock_connect, RPC_REESTABLISH_TIMEOUT); - else + else { schedule_work(&xprt->sock_connect); + if (!RPC_IS_ASYNC(task)) + flush_scheduled_work(); + } } return; out_write: @@ -1685,6 +1688,10 @@ xprt_shutdown(struct rpc_xprt *xprt) rpc_wake_up(&xprt->backlog); wake_up(&xprt->cong_wait); del_timer_sync(&xprt->timer); + + /* synchronously wait for connect worker to finish */ + cancel_delayed_work(&xprt->sock_connect); + flush_scheduled_work(); } /* -- cgit v0.10.2 From 00a926422765064cb28e218d4837411c88bf6a3e Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Wed, 22 Jun 2005 17:16:29 +0000 Subject: [PATCH] NFS: Hide NFS server-generated readdir cookies from userland NFSv3 currently returns the unsigned 64-bit cookie directly to userspace. The following patch causes the kernel to generate loff_t offsets for the benefit of userland. The current server-generated READDIR cookie is cached in the nfs_open_context instead of in filp->f_pos, so we still end up work correctly under directory insertions/deletion. Signed-off-by: Olivier Galibert Signed-off-by: Trond Myklebust diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 2c6a959..fceef29 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -141,7 +141,9 @@ typedef struct { struct page *page; unsigned long page_index; u32 *ptr; - u64 target; + u64 target_cookie; + int target_index; + int current_index; struct nfs_entry *entry; decode_dirent_t decode; int plus; @@ -225,14 +227,14 @@ void dir_page_release(nfs_readdir_descriptor_t *desc) /* * Given a pointer to a buffer that has already been filled by a call - * to readdir, find the next entry. + * to readdir, find the next entry with cookie 'desc->target_cookie'. * * If the end of the buffer has been reached, return -EAGAIN, if not, * return the offset within the buffer of the next entry to be * read. */ static inline -int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page) +int find_dirent(nfs_readdir_descriptor_t *desc) { struct nfs_entry *entry = desc->entry; int loop_count = 0, @@ -240,7 +242,7 @@ int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page) while((status = dir_decode(desc)) == 0) { dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie); - if (entry->prev_cookie == desc->target) + if (entry->prev_cookie == desc->target_cookie) break; if (loop_count++ > 200) { loop_count = 0; @@ -252,8 +254,44 @@ int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page) } /* - * Find the given page, and call find_dirent() in order to try to - * return the next entry. + * Given a pointer to a buffer that has already been filled by a call + * to readdir, find the entry at offset 'desc->target_index'. + * + * If the end of the buffer has been reached, return -EAGAIN, if not, + * return the offset within the buffer of the next entry to be + * read. + */ +static inline +int find_dirent_index(nfs_readdir_descriptor_t *desc) +{ + struct nfs_entry *entry = desc->entry; + int loop_count = 0, + status; + + for(;;) { + status = dir_decode(desc); + if (status) + break; + + dfprintk(VFS, "NFS: found cookie %Lu at index %d\n", (long long)entry->cookie, desc->current_index); + + if (desc->target_index == desc->current_index) { + desc->target_cookie = entry->cookie; + break; + } + desc->current_index++; + if (loop_count++ > 200) { + loop_count = 0; + schedule(); + } + } + dfprintk(VFS, "NFS: find_dirent_index() returns %d\n", status); + return status; +} + +/* + * Find the given page, and call find_dirent() or find_dirent_index in + * order to try to return the next entry. */ static inline int find_dirent_page(nfs_readdir_descriptor_t *desc) @@ -276,7 +314,10 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) /* NOTE: Someone else may have changed the READDIRPLUS flag */ desc->page = page; desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ - status = find_dirent(desc, page); + if (desc->target_cookie) + status = find_dirent(desc); + else + status = find_dirent_index(desc); if (status < 0) dir_page_release(desc); out: @@ -291,7 +332,8 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) * Recurse through the page cache pages, and return a * filled nfs_entry structure of the next directory entry if possible. * - * The target for the search is 'desc->target'. + * The target for the search is 'desc->target_cookie' if non-0, + * 'desc->target_index' otherwise */ static inline int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) @@ -299,7 +341,19 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) int loop_count = 0; int res; - dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target); + if (desc->target_cookie) + dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target_cookie); + else + dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie number %d\n", desc->target_index); + + /* Always search-by-index from the beginning of the cache */ + if (!(desc->target_cookie)) { + desc->page_index = 0; + desc->entry->cookie = desc->entry->prev_cookie = 0; + desc->entry->eof = 0; + desc->current_index = 0; + } + for (;;) { res = find_dirent_page(desc); if (res != -EAGAIN) @@ -332,11 +386,12 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, struct file *file = desc->file; struct nfs_entry *entry = desc->entry; struct dentry *dentry = NULL; + struct nfs_open_context *ctx = file->private_data; unsigned long fileid; int loop_count = 0, res; - dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)desc->target); + dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)entry->cookie); for(;;) { unsigned d_type = DT_UNKNOWN; @@ -356,10 +411,11 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, } res = filldir(dirent, entry->name, entry->len, - entry->prev_cookie, fileid, d_type); + file->f_pos, fileid, d_type); if (res < 0) break; - file->f_pos = desc->target = entry->cookie; + file->f_pos++; + desc->target_cookie = entry->cookie; if (dir_decode(desc) != 0) { desc->page_index ++; break; @@ -369,10 +425,12 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, schedule(); } } + ctx->dir_pos = file->f_pos; + ctx->dir_cookie = desc->target_cookie; dir_page_release(desc); if (dentry != NULL) dput(dentry); - dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target, res); + dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target_cookie, res); return res; } @@ -398,14 +456,14 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, struct page *page = NULL; int status; - dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target); + dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target_cookie); page = alloc_page(GFP_HIGHUSER); if (!page) { status = -ENOMEM; goto out; } - desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->target, + desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->target_cookie, page, NFS_SERVER(inode)->dtsize, desc->plus); @@ -414,7 +472,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ if (desc->error >= 0) { if ((status = dir_decode(desc)) == 0) - desc->entry->prev_cookie = desc->target; + desc->entry->prev_cookie = desc->target_cookie; } else status = -EIO; if (status < 0) @@ -435,13 +493,15 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, goto out; } -/* The file offset position is now represented as a true offset into the - * page cache as is the case in most of the other filesystems. +/* The file offset position represents the dirent entry number. A + last cookie cache takes care of the common case of reading the + whole directory. */ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; + struct nfs_open_context *ctx = filp->private_data; nfs_readdir_descriptor_t my_desc, *desc = &my_desc; struct nfs_entry my_entry; @@ -458,17 +518,22 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) } /* - * filp->f_pos points to the file offset in the page cache. - * but if the cache has meanwhile been zapped, we need to - * read from the last dirent to revalidate f_pos - * itself. + * filp->f_pos points to the dirent entry number. + * ctx->dir_pos has the number of the cached cookie. We have + * to either find the entry with the appropriate number or + * revalidate the cookie. */ memset(desc, 0, sizeof(*desc)); desc->file = filp; - desc->target = filp->f_pos; desc->decode = NFS_PROTO(inode)->decode_dirent; desc->plus = NFS_USE_READDIRPLUS(inode); + desc->target_index = filp->f_pos; + + if (filp->f_pos == ctx->dir_pos) + desc->target_cookie = ctx->dir_cookie; + else + desc->target_cookie = 0; my_entry.cookie = my_entry.prev_cookie = 0; my_entry.eof = 0; @@ -478,9 +543,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) while(!desc->entry->eof) { res = readdir_search_pagecache(desc); + if (res == -EBADCOOKIE) { /* This means either end of directory */ - if (desc->entry->cookie != desc->target) { + if (desc->target_cookie && desc->entry->cookie != desc->target_cookie) { /* Or that the server has 'lost' a cookie */ res = uncached_readdir(desc, dirent, filldir); if (res >= 0) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 8a8d57d..9fa02e7 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -891,6 +891,8 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp ctx->state = NULL; ctx->lockowner = current->files; ctx->error = 0; + ctx->dir_pos = 0; + ctx->dir_cookie = 0; } return ctx; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 4ceac9d..f810195 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -84,6 +84,9 @@ struct nfs_open_context { int error; struct list_head list; + + int dir_pos; /* Directory cookie cache */ + __u64 dir_cookie; }; /* -- cgit v0.10.2 From f0dd2136da6d2070e12bfa6d199b136318e666c7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:29 +0000 Subject: [PATCH] NFS: Clean up readdir changes. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index fceef29..b38a57e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -51,8 +51,10 @@ static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); static int nfs_fsync_dir(struct file *, struct dentry *, int); +static loff_t nfs_llseek_dir(struct file *, loff_t, int); struct file_operations nfs_dir_operations = { + .llseek = nfs_llseek_dir, .read = generic_read_dir, .readdir = nfs_readdir, .open = nfs_opendir, @@ -141,9 +143,8 @@ typedef struct { struct page *page; unsigned long page_index; u32 *ptr; - u64 target_cookie; - int target_index; - int current_index; + u64 *dir_cookie; + loff_t current_index; struct nfs_entry *entry; decode_dirent_t decode; int plus; @@ -227,7 +228,7 @@ void dir_page_release(nfs_readdir_descriptor_t *desc) /* * Given a pointer to a buffer that has already been filled by a call - * to readdir, find the next entry with cookie 'desc->target_cookie'. + * to readdir, find the next entry with cookie '*desc->dir_cookie'. * * If the end of the buffer has been reached, return -EAGAIN, if not, * return the offset within the buffer of the next entry to be @@ -241,8 +242,8 @@ int find_dirent(nfs_readdir_descriptor_t *desc) status; while((status = dir_decode(desc)) == 0) { - dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie); - if (entry->prev_cookie == desc->target_cookie) + dfprintk(VFS, "NFS: found cookie %Lu\n", (unsigned long long)entry->cookie); + if (entry->prev_cookie == *desc->dir_cookie) break; if (loop_count++ > 200) { loop_count = 0; @@ -255,7 +256,7 @@ int find_dirent(nfs_readdir_descriptor_t *desc) /* * Given a pointer to a buffer that has already been filled by a call - * to readdir, find the entry at offset 'desc->target_index'. + * to readdir, find the entry at offset 'desc->file->f_pos'. * * If the end of the buffer has been reached, return -EAGAIN, if not, * return the offset within the buffer of the next entry to be @@ -273,10 +274,10 @@ int find_dirent_index(nfs_readdir_descriptor_t *desc) if (status) break; - dfprintk(VFS, "NFS: found cookie %Lu at index %d\n", (long long)entry->cookie, desc->current_index); + dfprintk(VFS, "NFS: found cookie %Lu at index %Ld\n", (unsigned long long)entry->cookie, desc->current_index); - if (desc->target_index == desc->current_index) { - desc->target_cookie = entry->cookie; + if (desc->file->f_pos == desc->current_index) { + *desc->dir_cookie = entry->cookie; break; } desc->current_index++; @@ -314,7 +315,7 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) /* NOTE: Someone else may have changed the READDIRPLUS flag */ desc->page = page; desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ - if (desc->target_cookie) + if (*desc->dir_cookie != 0) status = find_dirent(desc); else status = find_dirent_index(desc); @@ -332,8 +333,8 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) * Recurse through the page cache pages, and return a * filled nfs_entry structure of the next directory entry if possible. * - * The target for the search is 'desc->target_cookie' if non-0, - * 'desc->target_index' otherwise + * The target for the search is '*desc->dir_cookie' if non-0, + * 'desc->file->f_pos' otherwise */ static inline int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) @@ -341,18 +342,15 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) int loop_count = 0; int res; - if (desc->target_cookie) - dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target_cookie); - else - dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie number %d\n", desc->target_index); - /* Always search-by-index from the beginning of the cache */ - if (!(desc->target_cookie)) { + if (*desc->dir_cookie == 0) { + dfprintk(VFS, "NFS: readdir_search_pagecache() searching for offset %Ld\n", (long long)desc->file->f_pos); desc->page_index = 0; desc->entry->cookie = desc->entry->prev_cookie = 0; desc->entry->eof = 0; desc->current_index = 0; - } + } else + dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); for (;;) { res = find_dirent_page(desc); @@ -386,7 +384,6 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, struct file *file = desc->file; struct nfs_entry *entry = desc->entry; struct dentry *dentry = NULL; - struct nfs_open_context *ctx = file->private_data; unsigned long fileid; int loop_count = 0, res; @@ -415,7 +412,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, if (res < 0) break; file->f_pos++; - desc->target_cookie = entry->cookie; + *desc->dir_cookie = entry->cookie; if (dir_decode(desc) != 0) { desc->page_index ++; break; @@ -425,12 +422,10 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, schedule(); } } - ctx->dir_pos = file->f_pos; - ctx->dir_cookie = desc->target_cookie; dir_page_release(desc); if (dentry != NULL) dput(dentry); - dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target_cookie, res); + dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res); return res; } @@ -456,14 +451,14 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, struct page *page = NULL; int status; - dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target_cookie); + dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); page = alloc_page(GFP_HIGHUSER); if (!page) { status = -ENOMEM; goto out; } - desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->target_cookie, + desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, *desc->dir_cookie, page, NFS_SERVER(inode)->dtsize, desc->plus); @@ -472,7 +467,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ if (desc->error >= 0) { if ((status = dir_decode(desc)) == 0) - desc->entry->prev_cookie = desc->target_cookie; + desc->entry->prev_cookie = *desc->dir_cookie; } else status = -EIO; if (status < 0) @@ -501,7 +496,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; - struct nfs_open_context *ctx = filp->private_data; nfs_readdir_descriptor_t my_desc, *desc = &my_desc; struct nfs_entry my_entry; @@ -519,21 +513,16 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) /* * filp->f_pos points to the dirent entry number. - * ctx->dir_pos has the number of the cached cookie. We have + * *desc->dir_cookie has the cookie for the next entry. We have * to either find the entry with the appropriate number or * revalidate the cookie. */ memset(desc, 0, sizeof(*desc)); desc->file = filp; + desc->dir_cookie = &((struct nfs_open_context *)filp->private_data)->dir_cookie; desc->decode = NFS_PROTO(inode)->decode_dirent; desc->plus = NFS_USE_READDIRPLUS(inode); - desc->target_index = filp->f_pos; - - if (filp->f_pos == ctx->dir_pos) - desc->target_cookie = ctx->dir_cookie; - else - desc->target_cookie = 0; my_entry.cookie = my_entry.prev_cookie = 0; my_entry.eof = 0; @@ -546,7 +535,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) if (res == -EBADCOOKIE) { /* This means either end of directory */ - if (desc->target_cookie && desc->entry->cookie != desc->target_cookie) { + if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) { /* Or that the server has 'lost' a cookie */ res = uncached_readdir(desc, dirent, filldir); if (res >= 0) @@ -579,6 +568,28 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) return 0; } +loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) +{ + down(&filp->f_dentry->d_inode->i_sem); + switch (origin) { + case 1: + offset += filp->f_pos; + case 0: + if (offset >= 0) + break; + default: + offset = -EINVAL; + goto out; + } + if (offset != filp->f_pos) { + filp->f_pos = offset; + ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0; + } +out: + up(&filp->f_dentry->d_inode->i_sem); + return offset; +} + /* * All directory operations under NFS are synchronous, so fsync() * is a dummy operation. diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 9fa02e7..6300e05 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -891,7 +891,6 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp ctx->state = NULL; ctx->lockowner = current->files; ctx->error = 0; - ctx->dir_pos = 0; ctx->dir_cookie = 0; } return ctx; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index f810195..c90313b 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -85,7 +85,6 @@ struct nfs_open_context { struct list_head list; - int dir_pos; /* Directory cookie cache */ __u64 dir_cookie; }; -- cgit v0.10.2 From 202b50dc127cf4714ffdcc6a64f1648373f9414f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:29 +0000 Subject: [PATCH] NFSv4: Ensure that propagate NFSv4 state errors to the reclaim code Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3f281a8..91e7fe8 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -269,14 +269,9 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta int err; do { err = _nfs4_open_reclaim(sp, state); - switch (err) { - case 0: - case -NFS4ERR_STALE_CLIENTID: - case -NFS4ERR_STALE_STATEID: - case -NFS4ERR_EXPIRED: - return err; - } - err = nfs4_handle_exception(server, err, &exception); + if (err != -NFS4ERR_DELAY) + break; + nfs4_handle_exception(server, err, &exception); } while (exception.retry); return err; } @@ -508,6 +503,20 @@ out_stale: goto out_nodeleg; } +static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) +{ + struct nfs_server *server = NFS_SERVER(dentry->d_inode); + struct nfs4_exception exception = { }; + int err; + + do { + err = _nfs4_open_expired(sp, state, dentry); + if (err == -NFS4ERR_DELAY) + nfs4_handle_exception(server, err, &exception); + } while (exception.retry); + return err; +} + static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) { struct nfs_inode *nfsi = NFS_I(state->inode); @@ -520,7 +529,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta continue; get_nfs_open_context(ctx); spin_unlock(&state->inode->i_lock); - status = _nfs4_open_expired(sp, state, ctx->dentry); + status = nfs4_do_open_expired(sp, state, ctx->dentry); put_nfs_open_context(ctx); return status; } @@ -2842,12 +2851,32 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) { - return _nfs4_do_setlk(state, F_SETLK, request, 1); + struct nfs_server *server = NFS_SERVER(state->inode); + struct nfs4_exception exception = { }; + int err; + + do { + err = _nfs4_do_setlk(state, F_SETLK, request, 1); + if (err != -NFS4ERR_DELAY) + break; + nfs4_handle_exception(server, err, &exception); + } while (exception.retry); + return err; } static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) { - return _nfs4_do_setlk(state, F_SETLK, request, 0); + struct nfs_server *server = NFS_SERVER(state->inode); + struct nfs4_exception exception = { }; + int err; + + do { + err = _nfs4_do_setlk(state, F_SETLK, request, 0); + if (err != -NFS4ERR_DELAY) + break; + nfs4_handle_exception(server, err, &exception); + } while (exception.retry); + return err; } static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) -- cgit v0.10.2 From 08e9eac42edab63bce14b5c8419771f3c92aa3f4 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:29 +0000 Subject: [PATCH] NFSv4: Fix up races in nfs4_proc_setattr() If we do not hold a valid stateid that is open for writes, there is little point in doing an extra open of the file, as the RFC does not appear to mandate this... Make setattr use the correct stateid if we're holding mandatory byte range locks. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 91e7fe8..af80b59 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -756,11 +756,10 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, fattr->valid = 0; - if (state != NULL) + if (state != NULL) { msg.rpc_cred = state->owner->so_cred; - if (sattr->ia_valid & ATTR_SIZE) - nfs4_copy_stateid(&arg.stateid, state, NULL); - else + nfs4_copy_stateid(&arg.stateid, state, current->files); + } else memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); return rpc_call_sync(server->client, &msg, 0); @@ -1124,47 +1123,31 @@ static int nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, struct iattr *sattr) { - struct inode * inode = dentry->d_inode; - int size_change = sattr->ia_valid & ATTR_SIZE; - struct nfs4_state *state = NULL; - int need_iput = 0; + struct rpc_cred *cred; + struct inode *inode = dentry->d_inode; + struct nfs4_state *state; int status; fattr->valid = 0; - if (size_change) { - struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); - if (IS_ERR(cred)) - return PTR_ERR(cred); + cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); + if (IS_ERR(cred)) + return PTR_ERR(cred); + /* Search for an existing WRITE delegation first */ + state = nfs4_open_delegated(inode, FMODE_WRITE, cred); + if (!IS_ERR(state)) { + /* NB: nfs4_open_delegated() bumps the inode->i_count */ + iput(inode); + } else { + /* Search for an existing open(O_WRITE) stateid */ state = nfs4_find_state(inode, cred, FMODE_WRITE); - if (state == NULL) { - state = nfs4_open_delegated(dentry->d_inode, - FMODE_WRITE, cred); - if (IS_ERR(state)) - state = nfs4_do_open(dentry->d_parent->d_inode, - dentry, FMODE_WRITE, - NULL, cred); - need_iput = 1; - } - put_rpccred(cred); - if (IS_ERR(state)) - return PTR_ERR(state); - - if (state->inode != inode) { - printk(KERN_WARNING "nfs: raced in setattr (%p != %p), returning -EIO\n", inode, state->inode); - status = -EIO; - goto out; - } } + status = nfs4_do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr, state); -out: - if (state) { - inode = state->inode; + if (state != NULL) nfs4_close_state(state, FMODE_WRITE); - if (need_iput) - iput(inode); - } + put_rpccred(cred); return status; } -- cgit v0.10.2 From 951a143b3fcf15cfa9d38250b7462f821db241db Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:30 +0000 Subject: [PATCH] NFS: Fix the file size revalidation Instead of looking at whether or not the file is open for writes before we accept to update the length using the server value, we should rather be looking at whether or not we are currently caching any writes. Failure to do so means in particular that we're not updating the file length correctly after obtaining a POSIX or BSD lock. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 68df803..d6a30c8 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -517,7 +517,7 @@ retry: result = tot_bytes; out: - nfs_end_data_update_defer(inode); + nfs_end_data_update(inode); nfs_writedata_free(wdata); return result; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6300e05..b2d1675 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1148,27 +1148,6 @@ void nfs_end_data_update(struct inode *inode) } /** - * nfs_end_data_update_defer - * @inode - pointer to inode - * Declare end of the operations that will update file data - * This will defer marking the inode as needing revalidation - * unless there are no other pending updates. - */ -void nfs_end_data_update_defer(struct inode *inode) -{ - struct nfs_inode *nfsi = NFS_I(inode); - - if (atomic_dec_and_test(&nfsi->data_updates)) { - /* Mark the attribute cache for revalidation */ - nfsi->flags |= NFS_INO_INVALID_ATTR; - /* Directories and symlinks: invalidate page cache too */ - if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) - nfsi->flags |= NFS_INO_INVALID_DATA; - nfsi->cache_change_attribute ++; - } -} - -/** * nfs_refresh_inode - verify consistency of the inode attribute cache * @inode - pointer to inode * @fattr - updated attributes @@ -1222,8 +1201,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) if (!timespec_equal(&inode->i_mtime, &fattr->mtime) || cur_size != new_isize) nfsi->flags |= NFS_INO_INVALID_ATTR; - } else if (S_ISREG(inode->i_mode) && new_isize > cur_size) - nfsi->flags |= NFS_INO_INVALID_ATTR; + } else if (new_isize != cur_size && nfsi->npages == 0) + nfsi->flags |= NFS_INO_INVALID_ATTR; /* Have any file permissions changed? */ if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) @@ -1257,10 +1236,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) { struct nfs_inode *nfsi = NFS_I(inode); - __u64 new_size; - loff_t new_isize; + loff_t cur_isize, new_isize; unsigned int invalid = 0; - loff_t cur_isize; int data_unstable; dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", @@ -1293,49 +1270,39 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign /* Are we racing with known updates of the metadata on the server? */ data_unstable = ! nfs_verify_change_attribute(inode, verifier); - /* Check if the file size agrees */ - new_size = fattr->size; + /* Check if our cached file size is stale */ new_isize = nfs_size_to_loff_t(fattr->size); cur_isize = i_size_read(inode); - if (cur_isize != new_size) { -#ifdef NFS_DEBUG_VERBOSE - printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); -#endif - /* - * If we have pending writebacks, things can get - * messy. - */ - if (S_ISREG(inode->i_mode) && data_unstable) { - if (new_isize > cur_isize) { + if (new_isize != cur_isize) { + /* Do we perhaps have any outstanding writes? */ + if (nfsi->npages == 0) { + /* No, but did we race with nfs_end_data_update()? */ + if (verifier == nfsi->cache_change_attribute) { inode->i_size = new_isize; - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; + invalid |= NFS_INO_INVALID_DATA; } - } else { + invalid |= NFS_INO_INVALID_ATTR; + } else if (new_isize > cur_isize) { inode->i_size = new_isize; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } + dprintk("NFS: isize change on server for file %s/%ld\n", + inode->i_sb->s_id, inode->i_ino); } - /* - * Note: we don't check inode->i_mtime since pipes etc. - * can change this value in VFS without requiring a - * cache revalidation. - */ + /* Check if the mtime agrees */ if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); -#ifdef NFS_DEBUG_VERBOSE - printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); -#endif + dprintk("NFS: mtime change on server for file %s/%ld\n", + inode->i_sb->s_id, inode->i_ino); if (!data_unstable) invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } if ((fattr->valid & NFS_ATTR_FATTR_V4) && nfsi->change_attr != fattr->change_attr) { -#ifdef NFS_DEBUG_VERBOSE - printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n", + dprintk("NFS: change_attr change on server for file %s/%ld\n", inode->i_sb->s_id, inode->i_ino); -#endif nfsi->change_attr = fattr->change_attr; if (!data_unstable) invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 6f7a4af..c574d55 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -220,7 +220,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, ClearPageError(page); io_error: - nfs_end_data_update_defer(inode); + nfs_end_data_update(inode); nfs_writedata_free(wdata); return written ? written : result; } @@ -401,7 +401,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) nfsi->npages--; if (!nfsi->npages) { spin_unlock(&nfsi->req_lock); - nfs_end_data_update_defer(inode); + nfs_end_data_update(inode); iput(inode); } else spin_unlock(&nfsi->req_lock); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index c90313b..211266c 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -294,7 +294,6 @@ extern void nfs_begin_attr_update(struct inode *); extern void nfs_end_attr_update(struct inode *); extern void nfs_begin_data_update(struct inode *); extern void nfs_end_data_update(struct inode *); -extern void nfs_end_data_update_defer(struct inode *); extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred); extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); extern void put_nfs_open_context(struct nfs_open_context *ctx); -- cgit v0.10.2 From 7d52e86274e09fce8ac8f963e3605a84d0a305a7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:30 +0000 Subject: [PATCH] NFS: Cleanup of caching code, and slight optimization of writes. Unless we're doing O_APPEND writes, we really don't care about revalidating the file length. Just make sure that we catch any page cache invalidations. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/file.c b/fs/nfs/file.c index a606708..4043685 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -333,9 +333,15 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t result = -EBUSY; if (IS_SWAPFILE(inode)) goto out_swapfile; - result = nfs_revalidate_inode(NFS_SERVER(inode), inode); - if (result) - goto out; + /* + * O_APPEND implies that we must revalidate the file length. + */ + if (iocb->ki_filp->f_flags & O_APPEND) { + result = nfs_revalidate_file_size(inode, iocb->ki_filp); + if (result) + goto out; + } else + nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); result = count; if (!count) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index b2d1675..a3922f4 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1062,21 +1062,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) if (verifier == nfsi->cache_change_attribute) nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); /* Do the page cache invalidation */ - if (flags & NFS_INO_INVALID_DATA) { - if (S_ISREG(inode->i_mode)) { - if (filemap_fdatawrite(inode->i_mapping) == 0) - filemap_fdatawait(inode->i_mapping); - nfs_wb_all(inode); - } - nfsi->flags &= ~NFS_INO_INVALID_DATA; - invalidate_inode_pages2(inode->i_mapping); - memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); - dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", - inode->i_sb->s_id, - (long long)NFS_FILEID(inode)); - /* This ensures we revalidate dentries */ - nfsi->cache_change_attribute++; - } + nfs_revalidate_mapping(inode, inode->i_mapping); if (flags & NFS_INO_INVALID_ACL) nfs_zap_acl_cache(inode); dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", @@ -1116,6 +1102,34 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) } /** + * nfs_revalidate_mapping - Revalidate the pagecache + * @inode - pointer to host inode + * @mapping - pointer to mapping + */ +void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + if (nfsi->flags & NFS_INO_INVALID_DATA) { + if (S_ISREG(inode->i_mode)) { + if (filemap_fdatawrite(mapping) == 0) + filemap_fdatawait(mapping); + nfs_wb_all(inode); + } + invalidate_inode_pages2(mapping); + nfsi->flags &= ~NFS_INO_INVALID_DATA; + if (S_ISDIR(inode->i_mode)) { + memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); + /* This ensures we revalidate child dentries */ + nfsi->cache_change_attribute++; + } + dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", + inode->i_sb->s_id, + (long long)NFS_FILEID(inode)); + } +} + +/** * nfs_begin_data_update * @inode - pointer to inode * Declare that a set of operations will update file data on the server diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 211266c..443103c 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -289,6 +289,7 @@ extern int nfs_release(struct inode *, struct file *); extern int nfs_attribute_timeout(struct inode *inode); extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode); extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); +extern void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); extern int nfs_setattr(struct dentry *, struct iattr *); extern void nfs_begin_attr_update(struct inode *); extern void nfs_end_attr_update(struct inode *); -- cgit v0.10.2 From fe51beecc55d0b0dce289e4758e7c529a642f63e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:30 +0000 Subject: [PATCH] NFS: Ensure that fstat() always returns the correct mtime Even if the file is open for writes. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 4043685..5621ba9 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -128,6 +128,21 @@ nfs_file_release(struct inode *inode, struct file *filp) } /** + * nfs_revalidate_file - Revalidate the page cache & related metadata + * @inode - pointer to inode struct + * @file - pointer to file + */ +static int nfs_revalidate_file(struct inode *inode, struct file *filp) +{ + int retval = 0; + + if ((NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode)) + retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode); + nfs_revalidate_mapping(inode, filp->f_mapping); + return 0; +} + +/** * nfs_revalidate_size - Revalidate the file size * @inode - pointer to inode struct * @file - pointer to struct file @@ -149,7 +164,8 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) goto force_reval; if (nfsi->npages != 0) return 0; - return nfs_revalidate_inode(server, inode); + if (!(NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) + return 0; force_reval: return __nfs_revalidate_inode(server, inode); } @@ -210,7 +226,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos) dentry->d_parent->d_name.name, dentry->d_name.name, (unsigned long) count, (unsigned long) pos); - result = nfs_revalidate_inode(NFS_SERVER(inode), inode); + result = nfs_revalidate_file(inode, iocb->ki_filp); if (!result) result = generic_file_aio_read(iocb, buf, count, pos); return result; @@ -228,7 +244,7 @@ nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count, dentry->d_parent->d_name.name, dentry->d_name.name, (unsigned long) count, (unsigned long long) *ppos); - res = nfs_revalidate_inode(NFS_SERVER(inode), inode); + res = nfs_revalidate_file(inode, filp); if (!res) res = generic_file_sendfile(filp, ppos, count, actor, target); return res; @@ -244,7 +260,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) dfprintk(VFS, "nfs: mmap(%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name); - status = nfs_revalidate_inode(NFS_SERVER(inode), inode); + status = nfs_revalidate_file(inode, file); if (!status) status = generic_file_mmap(file, vma); return status; @@ -340,8 +356,8 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t result = nfs_revalidate_file_size(inode, iocb->ki_filp); if (result) goto out; - } else - nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); + } + nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); result = count; if (!count) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index a3922f4..4f545f3 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -620,9 +620,9 @@ nfs_zap_caches(struct inode *inode) memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) - nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; + nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; else - nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; + nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; } static void nfs_zap_acl_cache(struct inode *inode) @@ -1055,6 +1055,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) goto out; } flags = nfsi->flags; + nfsi->flags &= ~NFS_INO_REVAL_PAGECACHE; /* * We may need to keep the attributes marked as invalid if * we raced with nfs_end_attr_update(). @@ -1187,8 +1188,11 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 && nfsi->change_attr == fattr->pre_change_attr) nfsi->change_attr = fattr->change_attr; - if (!data_unstable && nfsi->change_attr != fattr->change_attr) + if (nfsi->change_attr != fattr->change_attr) { nfsi->flags |= NFS_INO_INVALID_ATTR; + if (!data_unstable) + nfsi->flags |= NFS_INO_REVAL_PAGECACHE; + } } if ((fattr->valid & NFS_ATTR_FATTR) == 0) @@ -1211,12 +1215,16 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) } /* Verify a few of the more important attributes */ - if (!data_unstable) { - if (!timespec_equal(&inode->i_mtime, &fattr->mtime) - || cur_size != new_isize) - nfsi->flags |= NFS_INO_INVALID_ATTR; - } else if (new_isize != cur_size && nfsi->npages == 0) + if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { nfsi->flags |= NFS_INO_INVALID_ATTR; + if (!data_unstable) + nfsi->flags |= NFS_INO_REVAL_PAGECACHE; + } + if (cur_size != new_isize) { + nfsi->flags |= NFS_INO_INVALID_ATTR; + if (nfsi->npages == 0) + nfsi->flags |= NFS_INO_REVAL_PAGECACHE; + } /* Have any file permissions changed? */ if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 443103c..2954e44e 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -198,6 +198,7 @@ struct nfs_inode { #define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */ #define NFS_INO_INVALID_ACCESS 0x0040 /* cached access cred invalid */ #define NFS_INO_INVALID_ACL 0x0080 /* cached acls are invalid */ +#define NFS_INO_REVAL_PAGECACHE 0x1000 /* must revalidate pagecache */ static inline struct nfs_inode *NFS_I(struct inode *inode) { -- cgit v0.10.2 From ab0a3dbedc51037f3d2e22ef67717a987b3d15e2 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:30 +0000 Subject: [PATCH] NFS: Write optimization for short files and small O_SYNC writes. Use stable writes if we can see that we are only going to put a single write on the wire. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/write.c b/fs/nfs/write.c index c574d55..79b621a 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -750,7 +750,7 @@ int nfs_updatepage(struct file *file, struct page *page, * is entirely in cache, it may be more efficient to avoid * fragmenting write requests. */ - if (PageUptodate(page) && inode->i_flock == NULL) { + if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { loff_t end_offs = i_size_read(inode) - 1; unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT; @@ -1342,8 +1342,16 @@ static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, spin_lock(&nfsi->req_lock); res = nfs_scan_dirty(inode, &head, idx_start, npages); spin_unlock(&nfsi->req_lock); - if (res) - error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how); + if (res) { + struct nfs_server *server = NFS_SERVER(inode); + + /* For single writes, FLUSH_STABLE is more efficient */ + if (res == nfsi->npages && nfsi->npages <= server->wpages) { + if (res > 1 || nfs_list_entry(head.next)->wb_bytes <= server->wsize) + how |= FLUSH_STABLE; + } + error = nfs_flush_list(&head, server->wpages, how); + } if (error < 0) return error; return res; -- cgit v0.10.2 From c6a556b88adfacd2af90be84357c8165d716c27d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:30 +0000 Subject: [PATCH] NFS: Make searching and waiting on busy writeback requests more efficient. Basically copies the VFS's method for tracking writebacks and applies it to the struct nfs_page. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 80777f9..356a33b 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -112,6 +112,33 @@ void nfs_unlock_request(struct nfs_page *req) } /** + * nfs_set_page_writeback_locked - Lock a request for writeback + * @req: + */ +int nfs_set_page_writeback_locked(struct nfs_page *req) +{ + struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); + + if (!nfs_lock_request(req)) + return 0; + radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); + return 1; +} + +/** + * nfs_clear_page_writeback - Unlock request and wake up sleepers + */ +void nfs_clear_page_writeback(struct nfs_page *req) +{ + struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); + + spin_lock(&nfsi->req_lock); + radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); + spin_unlock(&nfsi->req_lock); + nfs_unlock_request(req); +} + +/** * nfs_clear_request - Free up all resources allocated to the request * @req: * @@ -301,7 +328,7 @@ nfs_scan_list(struct list_head *head, struct list_head *dst, if (req->wb_index > idx_end) break; - if (!nfs_lock_request(req)) + if (!nfs_set_page_writeback_locked(req)) continue; nfs_list_remove_request(req); nfs_list_add_request(req, dst); diff --git a/fs/nfs/read.c b/fs/nfs/read.c index a0042fb..6f866b8 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -173,7 +173,6 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, if (len < PAGE_CACHE_SIZE) memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); - nfs_lock_request(new); nfs_list_add_request(new, &one_request); nfs_pagein_one(&one_request, inode); return 0; @@ -185,7 +184,6 @@ static void nfs_readpage_release(struct nfs_page *req) nfs_clear_request(req); nfs_release_request(req); - nfs_unlock_request(req); dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", req->wb_context->dentry->d_inode->i_sb->s_id, @@ -553,7 +551,6 @@ readpage_async_filler(void *data, struct page *page) } if (len < PAGE_CACHE_SIZE) memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); - nfs_lock_request(new); nfs_list_add_request(new, desc->head); return 0; } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 79b621a..58a39b0 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -503,13 +503,12 @@ nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int spin_lock(&nfsi->req_lock); next = idx_start; - while (radix_tree_gang_lookup(&nfsi->nfs_page_tree, (void **)&req, next, 1)) { + while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { if (req->wb_index > idx_end) break; next = req->wb_index + 1; - if (!NFS_WBACK_BUSY(req)) - continue; + BUG_ON(!NFS_WBACK_BUSY(req)); atomic_inc(&req->wb_count); spin_unlock(&nfsi->req_lock); @@ -821,7 +820,7 @@ out: #else nfs_inode_remove_request(req); #endif - nfs_unlock_request(req); + nfs_clear_page_writeback(req); } static inline int flush_task_priority(int how) @@ -952,7 +951,7 @@ out_bad: nfs_writedata_free(data); } nfs_mark_request_dirty(req); - nfs_unlock_request(req); + nfs_clear_page_writeback(req); return -ENOMEM; } @@ -1002,7 +1001,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) struct nfs_page *req = nfs_list_entry(head->next); nfs_list_remove_request(req); nfs_mark_request_dirty(req); - nfs_unlock_request(req); + nfs_clear_page_writeback(req); } return -ENOMEM; } @@ -1029,7 +1028,7 @@ nfs_flush_list(struct list_head *head, int wpages, int how) req = nfs_list_entry(head->next); nfs_list_remove_request(req); nfs_mark_request_dirty(req); - nfs_unlock_request(req); + nfs_clear_page_writeback(req); } return error; } @@ -1121,7 +1120,7 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) nfs_inode_remove_request(req); #endif next: - nfs_unlock_request(req); + nfs_clear_page_writeback(req); } } @@ -1278,7 +1277,7 @@ nfs_commit_list(struct list_head *head, int how) req = nfs_list_entry(head->next); nfs_list_remove_request(req); nfs_mark_request_commit(req); - nfs_unlock_request(req); + nfs_clear_page_writeback(req); } return -ENOMEM; } @@ -1324,7 +1323,7 @@ nfs_commit_done(struct rpc_task *task) dprintk(" mismatch\n"); nfs_mark_request_dirty(req); next: - nfs_unlock_request(req); + nfs_clear_page_writeback(req); res++; } sub_page_state(nr_unstable,res); diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 39e4895..db40e45 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -20,6 +20,11 @@ #include /* + * Valid flags for the radix tree + */ +#define NFS_PAGE_TAG_WRITEBACK 1 + +/* * Valid flags for a dirty buffer */ #define PG_BUSY 0 @@ -62,6 +67,9 @@ extern int nfs_coalesce_requests(struct list_head *, struct list_head *, unsigned int); extern int nfs_wait_on_request(struct nfs_page *); extern void nfs_unlock_request(struct nfs_page *req); +extern int nfs_set_page_writeback_locked(struct nfs_page *req); +extern void nfs_clear_page_writeback(struct nfs_page *req); + /* * Lock the page of an asynchronous request without incrementing the wb_count @@ -96,10 +104,6 @@ nfs_list_remove_request(struct nfs_page *req) { if (list_empty(&req->wb_list)) return; - if (!NFS_WBACK_BUSY(req)) { - printk(KERN_ERR "NFS: unlocked request attempted removed from list!\n"); - BUG(); - } list_del_init(&req->wb_list); req->wb_list_head = NULL; } -- cgit v0.10.2 From 3da28eb1c6545fe73263a24eba0996217490e1eb Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:31 +0000 Subject: [PATCH] NFS: Replace nfs_page insertion sort with a radix sort Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 4f545f3..4845911 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -135,7 +135,7 @@ nfs_write_inode(struct inode *inode, int sync) int flags = sync ? FLUSH_WAIT : 0; int ret; - ret = nfs_commit_inode(inode, 0, 0, flags); + ret = nfs_commit_inode(inode, flags); if (ret < 0) return ret; return 0; diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 356a33b..d53857b 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -177,36 +177,6 @@ nfs_release_request(struct nfs_page *req) nfs_page_free(req); } -/** - * nfs_list_add_request - Insert a request into a sorted list - * @req: request - * @head: head of list into which to insert the request. - * - * Note that the wb_list is sorted by page index in order to facilitate - * coalescing of requests. - * We use an insertion sort that is optimized for the case of appended - * writes. - */ -void -nfs_list_add_request(struct nfs_page *req, struct list_head *head) -{ - struct list_head *pos; - -#ifdef NFS_PARANOIA - if (!list_empty(&req->wb_list)) { - printk(KERN_ERR "NFS: Add to list failed!\n"); - BUG(); - } -#endif - list_for_each_prev(pos, head) { - struct nfs_page *p = nfs_list_entry(pos); - if (p->wb_index < req->wb_index) - break; - } - list_add(&req->wb_list, pos); - req->wb_list_head = head; -} - static int nfs_wait_bit_interruptible(void *word) { int ret = 0; @@ -291,6 +261,62 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst, return npages; } +#define NFS_SCAN_MAXENTRIES 16 +/** + * nfs_scan_lock_dirty - Scan the radix tree for dirty requests + * @nfsi: NFS inode + * @dst: Destination list + * @idx_start: lower bound of page->index to scan + * @npages: idx_start + npages sets the upper bound to scan. + * + * Moves elements from one of the inode request lists. + * If the number of requests is set to 0, the entire address_space + * starting at index idx_start, is scanned. + * The requests are *not* checked to ensure that they form a contiguous set. + * You must be holding the inode's req_lock when calling this function + */ +int +nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, + unsigned long idx_start, unsigned int npages) +{ + struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; + struct nfs_page *req; + unsigned long idx_end; + int found, i; + int res; + + res = 0; + if (npages == 0) + idx_end = ~0; + else + idx_end = idx_start + npages - 1; + + for (;;) { + found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, + (void **)&pgvec[0], idx_start, NFS_SCAN_MAXENTRIES, + NFS_PAGE_TAG_DIRTY); + if (found <= 0) + break; + for (i = 0; i < found; i++) { + req = pgvec[i]; + if (req->wb_index > idx_end) + goto out; + + idx_start = req->wb_index + 1; + + if (nfs_set_page_writeback_locked(req)) { + radix_tree_tag_clear(&nfsi->nfs_page_tree, + req->wb_index, NFS_PAGE_TAG_DIRTY); + nfs_list_remove_request(req); + nfs_list_add_request(req, dst); + res++; + } + } + } +out: + return res; +} + /** * nfs_scan_list - Scan a list for matching requests * @head: One of the NFS inode request lists diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 58a39b0..5130eda 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -352,7 +352,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) if (err < 0) goto out; } - err = nfs_commit_inode(inode, 0, 0, wb_priority(wbc)); + err = nfs_commit_inode(inode, wb_priority(wbc)); if (err > 0) { wbc->nr_to_write -= err; err = 0; @@ -446,6 +446,8 @@ nfs_mark_request_dirty(struct nfs_page *req) struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&nfsi->req_lock); + radix_tree_tag_set(&nfsi->nfs_page_tree, + req->wb_index, NFS_PAGE_TAG_DIRTY); nfs_list_add_request(req, &nfsi->dirty); nfsi->ndirty++; spin_unlock(&nfsi->req_lock); @@ -537,12 +539,15 @@ static int nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) { struct nfs_inode *nfsi = NFS_I(inode); - int res; - res = nfs_scan_list(&nfsi->dirty, dst, idx_start, npages); - nfsi->ndirty -= res; - sub_page_state(nr_dirty,res); - if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) - printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); + int res = 0; + + if (nfsi->ndirty != 0) { + res = nfs_scan_lock_dirty(nfsi, dst, idx_start, npages); + nfsi->ndirty -= res; + sub_page_state(nr_dirty,res); + if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) + printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); + } return res; } @@ -561,11 +566,14 @@ static int nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) { struct nfs_inode *nfsi = NFS_I(inode); - int res; - res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); - nfsi->ncommit -= res; - if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) - printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); + int res = 0; + + if (nfsi->ncommit != 0) { + res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); + nfsi->ncommit -= res; + if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) + printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); + } return res; } #endif @@ -1209,36 +1217,24 @@ static void nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; - struct nfs_page *first, *last; + struct nfs_page *first; struct inode *inode; - loff_t start, end, len; /* Set up the RPC argument and reply structs * NB: take care not to mess about with data->commit et al. */ list_splice_init(head, &data->pages); first = nfs_list_entry(data->pages.next); - last = nfs_list_entry(data->pages.prev); inode = first->wb_context->dentry->d_inode; - /* - * Determine the offset range of requests in the COMMIT call. - * We rely on the fact that data->pages is an ordered list... - */ - start = req_offset(first); - end = req_offset(last) + last->wb_bytes; - len = end - start; - /* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */ - if (end >= i_size_read(inode) || len < 0 || len > (~((u32)0) >> 1)) - len = 0; - data->inode = inode; data->cred = first->wb_context->cred; data->args.fh = NFS_FH(data->inode); - data->args.offset = start; - data->args.count = len; - data->res.count = len; + /* Note: we always request a commit of the entire inode */ + data->args.offset = 0; + data->args.count = 0; + data->res.count = 0; data->res.fattr = &data->fattr; data->res.verf = &data->verf; @@ -1357,8 +1353,7 @@ static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, } #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) -int nfs_commit_inode(struct inode *inode, unsigned long idx_start, - unsigned int npages, int how) +int nfs_commit_inode(struct inode *inode, int how) { struct nfs_inode *nfsi = NFS_I(inode); LIST_HEAD(head); @@ -1366,15 +1361,13 @@ int nfs_commit_inode(struct inode *inode, unsigned long idx_start, error = 0; spin_lock(&nfsi->req_lock); - res = nfs_scan_commit(inode, &head, idx_start, npages); + res = nfs_scan_commit(inode, &head, 0, 0); + spin_unlock(&nfsi->req_lock); if (res) { - res += nfs_scan_commit(inode, &head, 0, 0); - spin_unlock(&nfsi->req_lock); error = nfs_commit_list(&head, how); - } else - spin_unlock(&nfsi->req_lock); - if (error < 0) - return error; + if (error < 0) + return error; + } return res; } #endif @@ -1396,7 +1389,7 @@ int nfs_sync_inode(struct inode *inode, unsigned long idx_start, error = nfs_flush_inode(inode, idx_start, npages, how); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) if (error == 0) - error = nfs_commit_inode(inode, idx_start, npages, how); + error = nfs_commit_inode(inode, how); #endif } while (error > 0); return error; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 2954e44e..8ea2491 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -395,10 +395,10 @@ extern void nfs_commit_done(struct rpc_task *); */ extern int nfs_sync_inode(struct inode *, unsigned long, unsigned int, int); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) -extern int nfs_commit_inode(struct inode *, unsigned long, unsigned int, int); +extern int nfs_commit_inode(struct inode *, int); #else static inline int -nfs_commit_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how) +nfs_commit_inode(struct inode *inode, int how) { return 0; } diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index db40e45..da2e077 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -22,6 +22,7 @@ /* * Valid flags for the radix tree */ +#define NFS_PAGE_TAG_DIRTY 0 #define NFS_PAGE_TAG_WRITEBACK 1 /* @@ -31,6 +32,7 @@ #define PG_NEED_COMMIT 1 #define PG_NEED_RESCHED 2 +struct nfs_inode; struct nfs_page { struct list_head wb_list, /* Defines state of page: */ *wb_list_head; /* read/write/commit */ @@ -59,8 +61,8 @@ extern void nfs_clear_request(struct nfs_page *req); extern void nfs_release_request(struct nfs_page *req); -extern void nfs_list_add_request(struct nfs_page *, struct list_head *); - +extern int nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, + unsigned long idx_start, unsigned int npages); extern int nfs_scan_list(struct list_head *, struct list_head *, unsigned long, unsigned int); extern int nfs_coalesce_requests(struct list_head *, struct list_head *, @@ -94,6 +96,18 @@ nfs_lock_request(struct nfs_page *req) return 1; } +/** + * nfs_list_add_request - Insert a request into a list + * @req: request + * @head: head of list into which to insert the request. + */ +static inline void +nfs_list_add_request(struct nfs_page *req, struct list_head *head) +{ + list_add_tail(&req->wb_list, head); + req->wb_list_head = head; +} + /** * nfs_list_remove_request - Remove a request from its wb_list -- cgit v0.10.2 From 80fec4c62e2cf544ac26e53f3e0d2f73df6820b9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:31 +0000 Subject: [PATCH] VFS: Ensure that all the on-stack struct file_lock call fl_release_private Signed-off-by: Trond Myklebust diff --git a/fs/locks.c b/fs/locks.c index 3fa6a7c..a0bc034 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1548,6 +1548,8 @@ int fcntl_getlk(struct file *filp, struct flock __user *l) if (filp->f_op && filp->f_op->lock) { error = filp->f_op->lock(filp, F_GETLK, &file_lock); + if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) + file_lock.fl_ops->fl_release_private(&file_lock); if (error < 0) goto out; else @@ -1690,6 +1692,8 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l) if (filp->f_op && filp->f_op->lock) { error = filp->f_op->lock(filp, F_GETLK, &file_lock); + if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) + file_lock.fl_ops->fl_release_private(&file_lock); if (error < 0) goto out; else @@ -1873,6 +1877,8 @@ void locks_remove_flock(struct file *filp) .fl_end = OFFSET_MAX, }; filp->f_op->flock(filp, F_SETLKW, &fl); + if (fl.fl_ops && fl.fl_ops->fl_release_private) + fl.fl_ops->fl_release_private(&fl); } lock_kernel(); -- cgit v0.10.2 From 4f15e2b1f4f3a56e46201714b39436c32218d547 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:31 +0000 Subject: [PATCH] NLM: cleanup for blocked locks. Signed-off-by: Trond Myklebust diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index ef7103b..44adb84 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -31,7 +31,7 @@ static int reclaimer(void *ptr); * This is the representation of a blocked client lock. */ struct nlm_wait { - struct nlm_wait * b_next; /* linked list */ + struct list_head b_list; /* linked list */ wait_queue_head_t b_wait; /* where to wait on */ struct nlm_host * b_host; struct file_lock * b_lock; /* local file lock */ @@ -39,7 +39,7 @@ struct nlm_wait { u32 b_status; /* grant callback status */ }; -static struct nlm_wait * nlm_blocked; +static LIST_HEAD(nlm_blocked); /* * Block on a lock @@ -55,8 +55,7 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) block.b_lock = fl; init_waitqueue_head(&block.b_wait); block.b_status = NLM_LCK_BLOCKED; - block.b_next = nlm_blocked; - nlm_blocked = █ + list_add(&block.b_list, &nlm_blocked); /* Remember pseudo nsm state */ pstate = host->h_state; @@ -71,12 +70,7 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) */ sleep_on_timeout(&block.b_wait, 30*HZ); - for (head = &nlm_blocked; *head; head = &(*head)->b_next) { - if (*head == &block) { - *head = block.b_next; - break; - } - } + list_del(&block.b_list); if (!signalled()) { *statp = block.b_status; @@ -105,7 +99,7 @@ nlmclnt_grant(struct nlm_lock *lock) * Look up blocked request based on arguments. * Warning: must not use cookie to match it! */ - for (block = nlm_blocked; block; block = block->b_next) { + list_for_each_entry(block, &nlm_blocked, b_list) { if (nlm_compare_locks(block->b_lock, &lock->fl)) break; } @@ -230,7 +224,7 @@ restart: host->h_reclaiming = 0; /* Now, wake up all processes that sleep on a blocked lock */ - for (block = nlm_blocked; block; block = block->b_next) { + list_for_each_entry(block, &nlm_blocked, b_list) { if (block->b_host == host) { block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; wake_up(&block->b_wait); -- cgit v0.10.2 From ecdbf769b2cb8903e07cd482334c714d89fd1146 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:31 +0000 Subject: [PATCH] NLM: fix a client-side race on blocking locks. If the lock blocks, the server may send us a GRANTED message that races with the reply to our LOCK request. Make sure that we catch the GRANTED by queueing up our request on the nlm_blocked list before we send off the first LOCK rpc call. Signed-off-by: Trond Myklebust diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 44adb84..006bb9e 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -42,23 +42,51 @@ struct nlm_wait { static LIST_HEAD(nlm_blocked); /* - * Block on a lock + * Queue up a lock for blocking so that the GRANTED request can see it */ -int -nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) +int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl) +{ + struct nlm_wait *block; + + BUG_ON(req->a_block != NULL); + block = kmalloc(sizeof(*block), GFP_KERNEL); + if (block == NULL) + return -ENOMEM; + block->b_host = host; + block->b_lock = fl; + init_waitqueue_head(&block->b_wait); + block->b_status = NLM_LCK_BLOCKED; + + list_add(&block->b_list, &nlm_blocked); + req->a_block = block; + + return 0; +} + +void nlmclnt_finish_block(struct nlm_rqst *req) { - struct nlm_wait block, **head; - int err; - u32 pstate; + struct nlm_wait *block = req->a_block; - block.b_host = host; - block.b_lock = fl; - init_waitqueue_head(&block.b_wait); - block.b_status = NLM_LCK_BLOCKED; - list_add(&block.b_list, &nlm_blocked); + if (block == NULL) + return; + req->a_block = NULL; + list_del(&block->b_list); + kfree(block); +} - /* Remember pseudo nsm state */ - pstate = host->h_state; +/* + * Block on a lock + */ +long nlmclnt_block(struct nlm_rqst *req, long timeout) +{ + struct nlm_wait *block = req->a_block; + long ret; + + /* A borken server might ask us to block even if we didn't + * request it. Just say no! + */ + if (!req->a_args.block) + return -EAGAIN; /* Go to sleep waiting for GRANT callback. Some servers seem * to lose callbacks, however, so we're going to poll from @@ -68,23 +96,16 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) * a 1 minute timeout would do. See the comment before * nlmclnt_lock for an explanation. */ - sleep_on_timeout(&block.b_wait, 30*HZ); + ret = wait_event_interruptible_timeout(block->b_wait, + block->b_status != NLM_LCK_BLOCKED, + timeout); - list_del(&block.b_list); - - if (!signalled()) { - *statp = block.b_status; - return 0; + if (block->b_status != NLM_LCK_BLOCKED) { + req->a_res.status = block->b_status; + block->b_status = NLM_LCK_BLOCKED; } - /* Okay, we were interrupted. Cancel the pending request - * unless the server has rebooted. - */ - if (pstate == host->h_state && (err = nlmclnt_cancel(host, fl)) < 0) - printk(KERN_NOTICE - "lockd: CANCEL call failed (errno %d)\n", -err); - - return -ERESTARTSYS; + return ret; } /* @@ -94,27 +115,23 @@ u32 nlmclnt_grant(struct nlm_lock *lock) { struct nlm_wait *block; + u32 res = nlm_lck_denied; /* * Look up blocked request based on arguments. * Warning: must not use cookie to match it! */ list_for_each_entry(block, &nlm_blocked, b_list) { - if (nlm_compare_locks(block->b_lock, &lock->fl)) - break; + if (nlm_compare_locks(block->b_lock, &lock->fl)) { + /* Alright, we found a lock. Set the return status + * and wake up the caller + */ + block->b_status = NLM_LCK_GRANTED; + wake_up(&block->b_wait); + res = nlm_granted; + } } - - /* Ooops, no blocked request found. */ - if (block == NULL) - return nlm_lck_denied; - - /* Alright, we found the lock. Set the return status and - * wake up the caller. - */ - block->b_status = NLM_LCK_GRANTED; - wake_up(&block->b_wait); - - return nlm_granted; + return res; } /* diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index a440761..fd77ed1 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -21,6 +21,7 @@ #define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMCLNT_GRACE_WAIT (5*HZ) +#define NLMCLNT_POLL_TIMEOUT (30*HZ) static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); @@ -553,7 +554,8 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) { struct nlm_host *host = req->a_host; struct nlm_res *resp = &req->a_res; - int status; + long timeout; + int status; if (!host->h_monitored && nsm_monitor(host) < 0) { printk(KERN_NOTICE "lockd: failed to monitor %s\n", @@ -562,15 +564,32 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) goto out; } - do { - if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) { - if (resp->status != NLM_LCK_BLOCKED) - break; - status = nlmclnt_block(host, fl, &resp->status); - } + if (req->a_args.block) { + status = nlmclnt_prepare_block(req, host, fl); if (status < 0) goto out; - } while (resp->status == NLM_LCK_BLOCKED && req->a_args.block); + } + for(;;) { + status = nlmclnt_call(req, NLMPROC_LOCK); + if (status < 0) + goto out_unblock; + if (resp->status != NLM_LCK_BLOCKED) + break; + /* Wait on an NLM blocking lock */ + timeout = nlmclnt_block(req, NLMCLNT_POLL_TIMEOUT); + /* Did a reclaimer thread notify us of a server reboot? */ + if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) + continue; + if (resp->status != NLM_LCK_BLOCKED) + break; + if (timeout >= 0) + continue; + /* We were interrupted. Send a CANCEL request to the server + * and exit + */ + status = (int)timeout; + goto out_unblock; + } if (resp->status == NLM_LCK_GRANTED) { fl->fl_u.nfs_fl.state = host->h_state; @@ -579,6 +598,11 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) do_vfs_lock(fl); } status = nlm_stat_to_errno(resp->status); +out_unblock: + nlmclnt_finish_block(req); + /* Cancel the blocked request if it is still pending */ + if (resp->status == NLM_LCK_BLOCKED) + nlmclnt_cancel(host, fl); out: nlmclnt_release_lockargs(req); return status; diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 0d9d225..16d4e5a 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -72,6 +72,8 @@ struct nlm_lockowner { uint32_t pid; }; +struct nlm_wait; + /* * Memory chunk for NLM client RPC request. */ @@ -81,6 +83,7 @@ struct nlm_rqst { struct nlm_host * a_host; /* host handle */ struct nlm_args a_args; /* arguments */ struct nlm_res a_res; /* result */ + struct nlm_wait * a_block; char a_owner[NLMCLNT_OHSIZE]; }; @@ -142,7 +145,9 @@ extern unsigned long nlmsvc_timeout; * Lockd client functions */ struct nlm_rqst * nlmclnt_alloc_call(void); -int nlmclnt_block(struct nlm_host *, struct file_lock *, u32 *); +int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl); +void nlmclnt_finish_block(struct nlm_rqst *req); +long nlmclnt_block(struct nlm_rqst *req, long timeout); int nlmclnt_cancel(struct nlm_host *, struct file_lock *); u32 nlmclnt_grant(struct nlm_lock *); void nlmclnt_recovery(struct nlm_host *, u32); -- cgit v0.10.2 From 8d0a8a9d0ec790086c64d210af413ac351d89e35 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:32 +0000 Subject: [PATCH] NFSv4: Clean up nfs4 lock state accounting Ensure that lock owner structures are not released prematurely. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 7c6f1d6..ec1a22d 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -128,6 +128,7 @@ struct nfs4_state_owner { struct nfs4_lock_state { struct list_head ls_locks; /* Other lock stateids */ + struct nfs4_state * ls_state; /* Pointer to open state */ fl_owner_t ls_owner; /* POSIX lock owner */ #define NFS_LOCK_INITIALIZED 1 int ls_flags; @@ -153,7 +154,7 @@ struct nfs4_state { unsigned long flags; /* Do we hold any locks? */ struct semaphore lock_sema; /* Serializes file locking operations */ - rwlock_t state_lock; /* Protects the lock_states list */ + spinlock_t state_lock; /* Protects the lock_states list */ nfs4_stateid stateid; @@ -225,12 +226,8 @@ extern void nfs4_close_state(struct nfs4_state *, mode_t); extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); extern void nfs4_schedule_state_recovery(struct nfs4_client *); -extern struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t); -extern struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t); -extern void nfs4_put_lock_state(struct nfs4_lock_state *state); +extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls); -extern void nfs4_notify_setlk(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *); -extern void nfs4_notify_unlck(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *); extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); extern const nfs4_stateid zero_stateid; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index af80b59..0ddc201 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2626,14 +2626,11 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock down_read(&clp->cl_sem); nlo.clientid = clp->cl_clientid; down(&state->lock_sema); - lsp = nfs4_find_lock_state(state, request->fl_owner); - if (lsp) - nlo.id = lsp->ls_id; - else { - spin_lock(&clp->cl_lock); - nlo.id = nfs4_alloc_lockowner_id(clp); - spin_unlock(&clp->cl_lock); - } + status = nfs4_set_lock_state(state, request); + if (status != 0) + goto out; + lsp = request->fl_u.nfs4_fl.owner; + nlo.id = lsp->ls_id; arg.u.lockt = &nlo; status = rpc_call_sync(server->client, &msg, 0); if (!status) { @@ -2654,8 +2651,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock request->fl_pid = 0; status = 0; } - if (lsp) - nfs4_put_lock_state(lsp); +out: up(&state->lock_sema); up_read(&clp->cl_sem); return status; @@ -2715,28 +2711,26 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock }; struct nfs4_lock_state *lsp; struct nfs_locku_opargs luargs; - int status = 0; + int status; down_read(&clp->cl_sem); down(&state->lock_sema); - lsp = nfs4_find_lock_state(state, request->fl_owner); - if (!lsp) + status = nfs4_set_lock_state(state, request); + if (status != 0) goto out; + lsp = request->fl_u.nfs4_fl.owner; /* We might have lost the locks! */ - if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) { - luargs.seqid = lsp->ls_seqid; - memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); - arg.u.locku = &luargs; - status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - nfs4_increment_lock_seqid(status, lsp); - } + if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) + goto out; + luargs.seqid = lsp->ls_seqid; + memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); + arg.u.locku = &luargs; + status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); + nfs4_increment_lock_seqid(status, lsp); - if (status == 0) { + if (status == 0) memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(lsp->ls_stateid)); - nfs4_notify_unlck(state, request, lsp); - } - nfs4_put_lock_state(lsp); out: up(&state->lock_sema); if (status == 0) @@ -2762,7 +2756,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r { struct inode *inode = state->inode; struct nfs_server *server = NFS_SERVER(inode); - struct nfs4_lock_state *lsp; + struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; struct nfs_lockargs arg = { .fh = NFS_FH(inode), .type = nfs4_lck_type(cmd, request), @@ -2784,9 +2778,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r }; int status; - lsp = nfs4_get_lock_state(state, request->fl_owner); - if (lsp == NULL) - return -ENOMEM; if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { struct nfs4_state_owner *owner = state->owner; struct nfs_open_to_lock otl = { @@ -2808,27 +2799,26 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r * seqid mutating errors */ nfs4_increment_seqid(status, owner); up(&owner->so_sema); + if (status == 0) { + lsp->ls_flags |= NFS_LOCK_INITIALIZED; + lsp->ls_seqid++; + } } else { struct nfs_exist_lock el = { .seqid = lsp->ls_seqid, }; memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); largs.u.exist_lock = ⪙ - largs.new_lock_owner = 0; arg.u.lock = &largs; status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); + /* increment seqid on success, and * seqid mutating errors*/ + nfs4_increment_lock_seqid(status, lsp); } - /* increment seqid on success, and * seqid mutating errors*/ - nfs4_increment_lock_seqid(status, lsp); /* save the returned stateid. */ - if (status == 0) { + if (status == 0) memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); - lsp->ls_flags |= NFS_LOCK_INITIALIZED; - if (!reclaim) - nfs4_notify_setlk(state, request, lsp); - } else if (status == -NFS4ERR_DENIED) + else if (status == -NFS4ERR_DENIED) status = -EAGAIN; - nfs4_put_lock_state(lsp); return status; } @@ -2869,7 +2859,9 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock down_read(&clp->cl_sem); down(&state->lock_sema); - status = _nfs4_do_setlk(state, cmd, request, 0); + status = nfs4_set_lock_state(state, request); + if (status == 0) + status = _nfs4_do_setlk(state, cmd, request, 0); up(&state->lock_sema); if (status == 0) { /* Note: we always want to sleep here! */ @@ -2927,7 +2919,6 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) if (signalled()) break; } while(status < 0); - return status; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 591ad1d..afe587d 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -360,7 +360,7 @@ nfs4_alloc_open_state(void) atomic_set(&state->count, 1); INIT_LIST_HEAD(&state->lock_states); init_MUTEX(&state->lock_sema); - rwlock_init(&state->state_lock); + spin_lock_init(&state->state_lock); return state; } @@ -542,16 +542,6 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) return NULL; } -struct nfs4_lock_state * -nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) -{ - struct nfs4_lock_state *lsp; - read_lock(&state->state_lock); - lsp = __nfs4_find_lock_state(state, fl_owner); - read_unlock(&state->state_lock); - return lsp; -} - /* * Return a compatible lock_state. If no initialized lock_state structure * exists, return an uninitialized one. @@ -568,14 +558,13 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f return NULL; lsp->ls_flags = 0; lsp->ls_seqid = 0; /* arbitrary */ - lsp->ls_id = -1; memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data)); atomic_set(&lsp->ls_count, 1); lsp->ls_owner = fl_owner; - INIT_LIST_HEAD(&lsp->ls_locks); spin_lock(&clp->cl_lock); lsp->ls_id = nfs4_alloc_lockowner_id(clp); spin_unlock(&clp->cl_lock); + INIT_LIST_HEAD(&lsp->ls_locks); return lsp; } @@ -585,121 +574,112 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f * * The caller must be holding state->lock_sema and clp->cl_sem */ -struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) +static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) { - struct nfs4_lock_state * lsp; + struct nfs4_lock_state *lsp, *new = NULL; - lsp = nfs4_find_lock_state(state, owner); - if (lsp == NULL) - lsp = nfs4_alloc_lock_state(state, owner); + for(;;) { + spin_lock(&state->state_lock); + lsp = __nfs4_find_lock_state(state, owner); + if (lsp != NULL) + break; + if (new != NULL) { + new->ls_state = state; + list_add(&new->ls_locks, &state->lock_states); + set_bit(LK_STATE_IN_USE, &state->flags); + lsp = new; + new = NULL; + break; + } + spin_unlock(&state->state_lock); + new = nfs4_alloc_lock_state(state, owner); + if (new == NULL) + return NULL; + } + spin_unlock(&state->state_lock); + kfree(new); return lsp; } /* - * Byte-range lock aware utility to initialize the stateid of read/write - * requests. + * Release reference to lock_state, and free it if we see that + * it is no longer in use */ -void -nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) +static void nfs4_put_lock_state(struct nfs4_lock_state *lsp) { - if (test_bit(LK_STATE_IN_USE, &state->flags)) { - struct nfs4_lock_state *lsp; + struct nfs4_state *state; - lsp = nfs4_find_lock_state(state, fl_owner); - if (lsp) { - memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); - nfs4_put_lock_state(lsp); - return; - } - } - memcpy(dst, &state->stateid, sizeof(*dst)); + if (lsp == NULL) + return; + state = lsp->ls_state; + if (!atomic_dec_and_lock(&lsp->ls_count, &state->state_lock)) + return; + list_del(&lsp->ls_locks); + if (list_empty(&state->lock_states)) + clear_bit(LK_STATE_IN_USE, &state->flags); + spin_unlock(&state->state_lock); + kfree(lsp); } -/* -* Called with state->lock_sema and clp->cl_sem held. -*/ -void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp) +static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) { - if (status == NFS_OK || seqid_mutating_err(-status)) - lsp->ls_seqid++; -} + struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner; -/* -* Check to see if the request lock (type FL_UNLK) effects the fl lock. -* -* fl and request must have the same posix owner -* -* return: -* 0 -> fl not effected by request -* 1 -> fl consumed by request -*/ + dst->fl_u.nfs4_fl.owner = lsp; + atomic_inc(&lsp->ls_count); +} -static int -nfs4_check_unlock(struct file_lock *fl, struct file_lock *request) +static void nfs4_fl_release_lock(struct file_lock *fl) { - if (fl->fl_start >= request->fl_start && fl->fl_end <= request->fl_end) - return 1; - return 0; + nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner); } -/* - * Post an initialized lock_state on the state->lock_states list. - */ -void nfs4_notify_setlk(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp) +static struct file_lock_operations nfs4_fl_lock_ops = { + .fl_copy_lock = nfs4_fl_copy_lock, + .fl_release_private = nfs4_fl_release_lock, +}; + +int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) { - if (!list_empty(&lsp->ls_locks)) - return; - atomic_inc(&lsp->ls_count); - write_lock(&state->state_lock); - list_add(&lsp->ls_locks, &state->lock_states); - set_bit(LK_STATE_IN_USE, &state->flags); - write_unlock(&state->state_lock); + struct nfs4_lock_state *lsp; + + if (fl->fl_ops != NULL) + return 0; + lsp = nfs4_get_lock_state(state, fl->fl_owner); + if (lsp == NULL) + return -ENOMEM; + fl->fl_u.nfs4_fl.owner = lsp; + fl->fl_ops = &nfs4_fl_lock_ops; + return 0; } -/* - * to decide to 'reap' lock state: - * 1) search i_flock for file_locks with fl.lock_state = to ls. - * 2) determine if unlock will consume found lock. - * if so, reap - * - * else, don't reap. - * +/* + * Byte-range lock aware utility to initialize the stateid of read/write + * requests. */ -void -nfs4_notify_unlck(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp) +void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) { - struct inode *inode = state->inode; - struct file_lock *fl; + struct nfs4_lock_state *lsp; - for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { - if (!(fl->fl_flags & FL_POSIX)) - continue; - if (fl->fl_owner != lsp->ls_owner) - continue; - /* Exit if we find at least one lock which is not consumed */ - if (nfs4_check_unlock(fl,request) == 0) - return; - } + memcpy(dst, &state->stateid, sizeof(*dst)); + if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) + return; - write_lock(&state->state_lock); - list_del_init(&lsp->ls_locks); - if (list_empty(&state->lock_states)) - clear_bit(LK_STATE_IN_USE, &state->flags); - write_unlock(&state->state_lock); + spin_lock(&state->state_lock); + lsp = __nfs4_find_lock_state(state, fl_owner); + if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) + memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); + spin_unlock(&state->state_lock); nfs4_put_lock_state(lsp); } /* - * Release reference to lock_state, and free it if we see that - * it is no longer in use - */ -void -nfs4_put_lock_state(struct nfs4_lock_state *lsp) +* Called with state->lock_sema and clp->cl_sem held. +*/ +void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp) { - if (!atomic_dec_and_test(&lsp->ls_count)) - return; - BUG_ON (!list_empty(&lsp->ls_locks)); - kfree(lsp); + if (status == NFS_OK || seqid_mutating_err(-status)) + lsp->ls_seqid++; } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 9b8b696..e5a8db0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -674,6 +674,7 @@ struct file_lock { struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */ union { struct nfs_lock_info nfs_fl; + struct nfs4_lock_info nfs4_fl; } fl_u; }; diff --git a/include/linux/nfs_fs_i.h b/include/linux/nfs_fs_i.h index e9a74958..e2c18dab 100644 --- a/include/linux/nfs_fs_i.h +++ b/include/linux/nfs_fs_i.h @@ -16,6 +16,11 @@ struct nfs_lock_info { struct nlm_lockowner *owner; }; +struct nfs4_lock_state; +struct nfs4_lock_info { + struct nfs4_lock_state *owner; +}; + /* * Lock flag values */ -- cgit v0.10.2 From 97d312d037e63e7c8ac004ffe3072f82a6d45495 Mon Sep 17 00:00:00 2001 From: Manoj Naik Date: Wed, 22 Jun 2005 17:16:39 +0000 Subject: [PATCH] NFSv4: add support for rdattr_error in NFSv4 readdir requests. Request RDATTR_ERROR as an attribute in readdir to distinguish between a directory being within an absent filesystem or one (or more) of its entries. Signed-off-by: Manoj Naik Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 325cd6d..4d655d2 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1014,6 +1014,10 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) { struct rpc_auth *auth = req->rq_task->tk_auth; + uint32_t attrs[2] = { + FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, + FATTR4_WORD1_MOUNTED_ON_FILEID, + }; int replen; uint32_t *p; @@ -1024,13 +1028,13 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ WRITE32(readdir->count); WRITE32(2); - if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) { - WRITE32(0); - WRITE32(FATTR4_WORD1_MOUNTED_ON_FILEID); - } else { - WRITE32(FATTR4_WORD0_FILEID); - WRITE32(0); - } + /* Switch to mounted_on_fileid if the server supports it */ + if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) + attrs[0] &= ~FATTR4_WORD0_FILEID; + else + attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; + WRITE32(attrs[0] & readdir->bitmask[0]); + WRITE32(attrs[1] & readdir->bitmask[1]); /* set up reply kvec * toplevel_status + taglen + rescount + OP_PUTFH + status @@ -4060,6 +4064,12 @@ uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) } len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ if (len > 0) { + if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) { + bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; + /* Ignore the return value of rdattr_error for now */ + p++; + len--; + } if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) xdr_decode_hyper(p, &entry->ino); else if (bitmap[0] == FATTR4_WORD0_FILEID) -- cgit v0.10.2 From 6ebf3656fd18430d90fbb3199b31d08178c37134 Mon Sep 17 00:00:00 2001 From: Manoj Naik Date: Wed, 22 Jun 2005 17:16:39 +0000 Subject: [PATCH] NFSv4: Map a couple of NFSv4 errors to EINVAL. This shows up on running tar over NFSv4. Signed-off-by: Manoj Naik Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 4d655d2..577b442 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4109,6 +4109,8 @@ static struct { { NFS4ERR_DQUOT, EDQUOT }, { NFS4ERR_STALE, ESTALE }, { NFS4ERR_BADHANDLE, EBADHANDLE }, + { NFS4ERR_BADOWNER, EINVAL }, + { NFS4ERR_BADNAME, EINVAL }, { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, { NFS4ERR_NOTSUPP, ENOTSUPP }, { NFS4ERR_TOOSMALL, ETOOSMALL }, -- cgit v0.10.2 From eadf4598e7ec37a234e70e965bd335860e58bda4 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2005 17:16:39 +0000 Subject: [PATCH] NFS: Add debugging code to NFSv4 readdir Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0ddc201..1b76f80 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1722,6 +1722,10 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, }; int status; + dprintk("%s: dentry = %s/%s, cookie = %Lu\n", __FUNCTION__, + dentry->d_parent->d_name.name, + dentry->d_name.name, + (unsigned long long)cookie); lock_kernel(); nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); res.pgbase = args.pgbase; @@ -1729,6 +1733,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, if (status == 0) memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); unlock_kernel(); + dprintk("%s: returns %d\n", __FUNCTION__, status); return status; } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 577b442..6c564ef 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1035,6 +1035,13 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; WRITE32(attrs[0] & readdir->bitmask[0]); WRITE32(attrs[1] & readdir->bitmask[1]); + dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n", + __FUNCTION__, + (unsigned long long)readdir->cookie, + ((u32 *)readdir->verifier.data)[0], + ((u32 *)readdir->verifier.data)[1], + attrs[0] & readdir->bitmask[0], + attrs[1] & readdir->bitmask[1]); /* set up reply kvec * toplevel_status + taglen + rescount + OP_PUTFH + status @@ -1043,6 +1050,9 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, readdir->pgbase, readdir->count); + dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", + __FUNCTION__, replen, readdir->pages, + readdir->pgbase, readdir->count); return 0; } @@ -3066,6 +3076,11 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n return status; READ_BUF(8); COPYMEM(readdir->verifier.data, 8); + dprintk("%s: verifier = 0x%x%x\n", + __FUNCTION__, + ((u32 *)readdir->verifier.data)[0], + ((u32 *)readdir->verifier.data)[1]); + hdrlen = (char *) p - (char *) iov->iov_base; recvd = rcvbuf->len - hdrlen; @@ -3080,12 +3095,14 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n for (nr = 0; *p++; nr++) { if (p + 3 > end) goto short_pkt; + dprintk("cookie = %Lu, ", *((unsigned long long *)p)); p += 2; /* cookie */ len = ntohl(*p++); /* filename length */ if (len > NFS4_MAXNAMLEN) { printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); goto err_unmap; } + dprintk("filename = %*s\n", len, (char *)p); p += XDR_QUADLEN(len); if (p + 1 > end) goto short_pkt; @@ -3105,6 +3122,7 @@ out: kunmap_atomic(kaddr, KM_USER0); return 0; short_pkt: + dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); entry[0] = entry[1] = 0; /* truncate listing ? */ if (!nr) { -- cgit v0.10.2 From f1b04770b0d073a9d70e5b3b873d274c1c19e1f6 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 22 Jun 2005 15:10:02 -0500 Subject: [PATCH] ppc32: Fix building MPC8555 CDS Adding support for MPC8548 w/o PCI support, broke building MPC8555 CDS by trying to remove a loop variable that was used when PCI is enabled. Signed-off-by: Kumar Gala Signed-off-by: Linus Torvalds bi_immr_base + MPC85xx_OPENPIC_OFFSET; -- cgit v0.10.2 From b46a58fd4e3cdd107ffccedaa5e233deeb94c5c0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 22 Jun 2005 21:25:58 +0100 Subject: [PATCH] ARM: Use list_for_each_entry() for dmabounce Convert dmabounce.c to use list_for_each_entry() instead of list_for_each() + list_entry(). Signed-off-by: Russell King diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 9d63a01..cbf2165 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -93,15 +93,12 @@ static void print_alloc_stats(struct dmabounce_device_info *device_info) static inline struct dmabounce_device_info * find_dmabounce_dev(struct device *dev) { - struct list_head *entry; - - list_for_each(entry, &dmabounce_devs) { - struct dmabounce_device_info *d = - list_entry(entry, struct dmabounce_device_info, node); + struct dmabounce_device_info *d; + list_for_each_entry(d, &dmabounce_devs, node) if (d->dev == dev) return d; - } + return NULL; } @@ -172,15 +169,11 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr, static inline struct safe_buffer * find_safe_buffer(struct dmabounce_device_info *device_info, dma_addr_t safe_dma_addr) { - struct list_head *entry; - - list_for_each(entry, &device_info->safe_buffers) { - struct safe_buffer *b = - list_entry(entry, struct safe_buffer, node); + struct safe_buffer *b; + list_for_each_entry(b, &device_info->safe_buffers, node) if (b->safe_dma_addr == safe_dma_addr) return b; - } return NULL; } @@ -301,7 +294,6 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, __func__, buf->ptr, (void *) virt_to_dma(dev, buf->ptr), buf->safe, (void *) buf->safe_dma_addr); - DO_STATS ( device_info->bounce_count++ ); if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { -- cgit v0.10.2 From 3a66941106855215127f8bf1afd06099b72dc75b Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 22 Jun 2005 21:43:10 +0100 Subject: [PATCH] ARM: Ensure memory information is page aligned Ensure that meminfo.bank[] array contains page-aligned start/size information. Signed-off-by: Russell King diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 9fed5fa..8cf733d 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -395,6 +395,20 @@ static void __init early_initrd(char **p) } __early_param("initrd=", early_initrd); +static void __init add_memory(unsigned long start, unsigned long size) +{ + /* + * Ensure that start/size are aligned to a page boundary. + * Size is appropriately rounded down, start is rounded up. + */ + size -= start & ~PAGE_MASK; + + meminfo.bank[meminfo.nr_banks].start = PAGE_ALIGN(start); + meminfo.bank[meminfo.nr_banks].size = size & PAGE_MASK; + meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(start); + meminfo.nr_banks += 1; +} + /* * Pick out the memory size. We look for mem=size@start, * where start and size are "size[KkMm]" @@ -419,10 +433,7 @@ static void __init early_mem(char **p) if (**p == '@') start = memparse(*p + 1, p); - meminfo.bank[meminfo.nr_banks].start = start; - meminfo.bank[meminfo.nr_banks].size = size; - meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(start); - meminfo.nr_banks += 1; + add_memory(start, size); } __early_param("mem=", early_mem); @@ -564,11 +575,7 @@ static int __init parse_tag_mem32(const struct tag *tag) tag->u.mem.start, tag->u.mem.size / 1024); return -EINVAL; } - meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start; - meminfo.bank[meminfo.nr_banks].size = tag->u.mem.size; - meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(tag->u.mem.start); - meminfo.nr_banks += 1; - + add_memory(tag->u.mem.start, tag->u.mem.size); return 0; } -- cgit v0.10.2 From 92a8cbed29eb9bf6e8eec16ca29d54015bc0e8a2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 22 Jun 2005 21:47:25 +0100 Subject: [PATCH] ARM: Remove explicit page-alignments in memory init Since meminfo.bank[] array contains page-aligned start/size, we no longer need to explicitly round up/down the addresses when converting to PFNs. Signed-off-by: Russell King diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 72a2b8c..c08710b 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -93,14 +93,7 @@ struct node_info { }; #define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define V_PFN_DOWN(x) O_PFN_DOWN(__pa(x)) - #define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT) -#define V_PFN_UP(x) O_PFN_UP(__pa(x)) - -#define PFN_SIZE(x) ((x) >> PAGE_SHIFT) -#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \ - (((unsigned long)(s)) & PAGE_MASK)) /* * FIXME: We really want to avoid allocating the bootmap bitmap @@ -113,7 +106,7 @@ find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages) { unsigned int start_pfn, bank, bootmap_pfn; - start_pfn = V_PFN_UP(&_end); + start_pfn = O_PFN_UP(__pa(&_end)); bootmap_pfn = 0; for (bank = 0; bank < mi->nr_banks; bank ++) { @@ -122,9 +115,9 @@ find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages) if (mi->bank[bank].node != node) continue; - start = O_PFN_UP(mi->bank[bank].start); - end = O_PFN_DOWN(mi->bank[bank].size + - mi->bank[bank].start); + start = mi->bank[bank].start >> PAGE_SHIFT; + end = (mi->bank[bank].size + + mi->bank[bank].start) >> PAGE_SHIFT; if (end < start_pfn) continue; @@ -191,8 +184,8 @@ find_memend_and_nodes(struct meminfo *mi, struct node_info *np) /* * Get the start and end pfns for this bank */ - start = O_PFN_UP(mi->bank[i].start); - end = O_PFN_DOWN(mi->bank[i].start + mi->bank[i].size); + start = mi->bank[i].start >> PAGE_SHIFT; + end = (mi->bank[i].start + mi->bank[i].size) >> PAGE_SHIFT; if (np[node].start > start) np[node].start = start; -- cgit v0.10.2